1. לפני שמתחילים
ממשקי ה-API של Google Home מספקים למפתחי Android קבוצה של ספריות שמאפשרות להם להשתמש בסביבת Google Home. בעזרת ה-APIs החדשים האלה, מפתחים יכולים ליצור אפליקציות שמבצעות צירוף ושליטה במכשירי בית חכם בצורה חלקה.
הסרטון הזה מספק הדרכה מפורטת קצרה על האפליקציה לנייד שתבנו, לכן מומלץ לעקוב אחר הסרטון תוך כדי ביצוע ה-Codelab.
Google מספקת אפליקציה לדוגמה ל-Android למפתחים שרוצים לגשת לדוגמה פעילה באמצעות ממשקי Google Home API. ה-Codelab הזה מבוסס על הסתעפות של אפליקציית הדוגמה, ומסביר איך להשתמש בממשקי ה-API של הרשאות, הפעלה, מכשיר ומבנה.
דרישות מוקדמות
- ידע במערכת האקולוגית של Google Home (Cloud-to-cloud ו-Matter).
- תחנת עבודה עם Android Studio (גרסה 2024.3.1 Ladybug ואילך) מותקנת.
- טלפון Android שעומד בדרישות של ממשקי ה-API של Home (ראו דרישות מוקדמות) עם Google Play Services ואפליקציית Google Home מותקנים. אי אפשר להשתמש באמולטור, יש תמיכה רק בטלפונים פיזיים עם Android עבור אפליקציית הדוגמה.
- Google Home Hub תואם שתומך ב-Google Home APIs.
- אופציונלי – מכשיר לבית חכם שתואם לממשקי Google Home API.
מה תלמדו
- איך מפתחים אפליקציית Android באמצעות ממשקי Google Home API, תוך שימוש בשיטות מומלצות.
- איך משתמשים בממשקי ה-API של מכשירים ומבנים כדי לייצג בית חכם ולשלוט בו.
- איך משתמשים בממשקי API להוספת מכשירים למערכת האקולוגית של Google Home.
אופציונלי: הגדרת הבית
לפני שמשתמשים בממשקי Google Home API, צריך להגדיר בית בחשבון Google באמצעות אפליקציית Google Home ולהוסיף כמה מכשירים. בקטע הזה מוסבר איך עושים את זה באמצעות Google Home Playground, שכולל מכשירים וירטואליים לבית החכם.
פותחים את home-playground.withgoogle.com בדפדפן האינטרנט, נכנסים לחשבון Google ובודקים אם מופיעים המכשירים המדומים הבאים:
- outlet1: On/Off plug
- light2: Dimmable light
- light3: הפעלה/השבתה של התאורה
- ac3: מזגן
- blinds4: Window Covering
- washer5: Smart washer

פותחים את אפליקציית Google Home בנייד, מקישים על הלחצן הוספה ובוחרים באפשרות עובד עם Google Home. מחפשים את האפשרות playground ברשימה, בוחרים בפרויקט Google Home Playground ומקישים על המשך.



יוצג לכם דף הרשאה לחשבון ב-Google Home Playground. מקישים על אישור או על כניסה באמצעות חשבון Google. כל המכשירים שהגדרתם באפליקציית האינטרנט יופיעו באפליקציה לנייד.


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

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

- קוד האפליקציה: קוד הליבה שעליו עובדים המפתחים כדי לבנות את ממשק המשתמש של האפליקציה ואת הלוגיקה לאינטראקציה עם Home APIs SDK.
- Home APIs SDK: ערכת ה-SDK של Home APIs ש-Google מספקת פועלת עם שירות Home APIs ב-GMSCore כדי לשלוט במכשירי בית חכם. מפתחים בונים אפליקציות שעובדות עם ממשקי ה-API של Home על ידי קיבוץ שלהן עם ערכת ה-SDK של ממשקי ה-API של Home.
- GMSCore ב-Android: GMSCore, שנקרא גם Google Play Services, הוא פלטפורמה של Google שמספקת שירותי ליבה למערכת, ומאפשרת להפעיל תכונות חשובות בכל מכשירי Android שאושרו. מודול הבית של Google Play Services מכיל את השירותים שמקיימים אינטראקציה עם ממשקי ה-API של Home.
הגדרת Home SDK
כדי לקבל את ה-SDK העדכני ביותר, פועלים לפי השלבים שמפורטים במאמר בנושא הגדרת ה-SDK.
הורדת האפליקציה לדוגמה
קוד המקור של האפליקציה לדוגמה זמין ב-GitHub. ב-codelab הזה נעשה שימוש בדוגמאות מההסתעפות codelab-branch-1 של האפליקציה לדוגמה.
עוברים למיקום שבו רוצים לשמור את הפרויקט ומשכפלים את ההסתעפות codelab-branch-1:
$ git clone -b codelab-branch-1 https://github.com/google-home/google-home-api-sample-app-android.git
יצירת אפליקציה לדוגמה
מבצעים את השלבים 1 עד 5 בקטע פיתוח האפליקציה.

כשהאפליקציה תפעל בהצלחה בטלפון, יוצג הדף הראשי של אפליקציית הדוגמה. אבל לא תוכלו להיכנס עד שתגדירו אימות OAuth ותטמיעו את החלקים החסרים באמצעות Permission API.
3. הגדרת אימות
ממשקי ה-API של Home משתמשים ב-OAuth 2.0 כדי להעניק גישה למכשירים במבנה. פרוטוקול OAuth מאפשר למשתמש להעניק הרשאה לאפליקציה או לשירות בלי לחשוף את פרטי הכניסה שלו.
פועלים לפי ההוראות במאמר הגדרת הסכמה ל-OAuth כדי להגדיר את מסך ההסכמה. חשוב ליצור לפחות חשבון בדיקה אחד.
לאחר מכן פועלים לפי ההוראות שבמאמר הגדרת פרטי כניסה של OAuth כדי ליצור את פרטי הכניסה לאפליקציה.
4. הפעלה וניהול הרשאות
בקטע הזה נסביר איך לאתחל את ה-SDK ולטפל בהרשאות משתמשים באמצעות Permissions API.
הגדרת סוגים ומאפיינים נתמכים
כשמפתחים אפליקציה, צריך לציין במפורש אילו סוגי מכשירים ומאפיינים האפליקציה תתמוך בהם. באפליקציה לדוגמה, אנחנו מגדירים רשימות סטטיות באובייקט הנלווה ב-HomeApp.kt, שאפשר להפנות אליו בכל מקום באפליקציה לפי הצורך:
companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
OnOffLightDevice,
DimmableLightDevice,
// ...
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
OnOff,
LevelControl,
// ...
)
}
במאמרים סוגי מכשירים נתמכים ומדד ה-Trait ב-Android אפשר לראות את כל סוגי המכשירים וה-Traits הנתמכים.
לבטל סימון כהערה בשלבים 4.1.1 ו-4.1.2 בקובץ המקור HomeApp.kt כדי להפעיל את קוד המקור שמבקש את ההרשאה.
companion object {
// List of supported device types by this app:
val supportedTypes: List<DeviceTypeFactory<out DeviceType>> = listOf(
// TODO: 4.1.1 - Non-registered device types will be unsupported
// ContactSensorDevice,
// ColorTemperatureLightDevice,
// DimmableLightDevice,
// ExtendedColorLightDevice,
// GenericSwitchDevice,
// GoogleDisplayDevice,
// GoogleTVDevice,
// OccupancySensorDevice,
// OnOffLightDevice,
// OnOffLightSwitchDevice,
// OnOffPluginUnitDevice,
// OnOffSensorDevice,
// RootNodeDevice,
// SpeakerDevice,
// ThermostatDevice,
)
// List of supported device traits by this app:
val supportedTraits: List<TraitFactory<out Trait>> = listOf(
// TODO: 4.1.2 - Non-registered traits will be unsupported
// AreaAttendanceState,
// AreaPresenceState,
// Assistant,
// AssistantBroadcast,
// AssistantFulfillment,
// BasicInformation,
// BooleanState,
// OccupancySensing,
// OnOff,
// Notification,
// LevelControl,
// TemperatureControl,
// TemperatureMeasurement,
// Thermostat,
// Time,
// Volume,
)
}
אתחול האובייקט HomeClient
כל האפליקציות שמשתמשות בממשקי ה-API של Home מאתחלות אובייקט HomeClient, שהוא הממשק הראשי לאינטראקציה עם ממשקי ה-API. אנחנו מכינים את האובייקט הזה בשיטת האתחול של המחלקה HomeApp (HomeApp.kt).
// Registry to record device types and traits used in this app:
val registry = FactoryRegistry(
types = supportedTypes,
traits = supportedTraits
)
// Configuration options for the HomeClient:
val config = HomeConfig(
coroutineContext = Dispatchers.IO,
factoryRegistry = registry
)
// Initialize the HomeClient, which is the primary object to use all Home APIs:
homeClient = Home.getClient(context = context, homeConfig = config)
קודם יוצרים FactoryRegistry באמצעות הסוגים והמאפיינים הנתמכים שהגדרנו קודם. לאחר מכן, באמצעות המאגר הזה, מאתחלים HomeConfig, שמכיל את ההגדרות שנדרשות להפעלת ממשקי ה-API. לאחר מכן אנחנו משתמשים בקריאה Home.getClient(...) כדי לקבל את מופע HomeClient.
כל האינטראקציות שלנו עם ממשקי ה-API של Home יהיו דרך אובייקט HomeClient הזה.
שימוש ב-Permissions API
אימות המשתמשים ב-Home APIs מתבצע באמצעות Permissions API. קובץ המקור PermissionsManager.kt של אפליקציית הדוגמה מכיל קוד לאימות משתמשים. בטלו את סימון התוכן כהערה של הפונקציות checkPermissions(...) ו-requestPermissions(...) כדי להפעיל את ההרשאות של אפליקציית הדוגמה.
רישום:
homeClient.registerActivityResultCallerForPermissions(activity)
הפעלה:
try {
val result: PermissionsResult
result = homeClient.requestPermissions(forceLaunch = true)
when (result.status) {
PermissionsResultStatus.SUCCESS -> // Success Case
PermissionsResultStatus.CANCELLED -> // User Cancelled
PermissionsResultStatus.ERROR -> // Some Error
else -> // Unsupported Case
}
}
catch (e: HomeException) { ... }
בדיקה:
try {
val state: PermissionsState
state = homeClient.hasPermissions().first { state ->
state != PermissionsState.PERMISSIONS_STATE_UNINITIALIZED
}
when (state) {
PermissionsState.GRANTED -> // Signed In
PermissionsState.NOT_GRANTED -> // Not Signed In
PermissionsState.PERMISSIONS_STATE_UNAVAILABLE -> // ...
PermissionsState.PERMISSIONS_STATE_UNINITIALIZED -> // ...
else -> // Unsupported case
}
}
catch (e: HomeException) { ... }
הרשמה למינוי:
homeClient.hasPermissions().collect( { state ->
// Track the changes on state
} )
לבטל סימון כהערה בשלב 4.3.1 ב-PermissionsManager.kt כדי להפעיל את הקוד שמבקש את ההרשאות:
fun requestPermissions() {
scope.launch {
try {
// TODO: 4.3.1 - Request the permissions from the Permissions API
// // Request permissions from the Permissions API and record the result:
// val result: PermissionsResult = client.requestPermissions(forceLaunch = true)
// // Adjust the sign-in status according to permission result:
// if (result.status == PermissionsResultStatus.SUCCESS)
// isSignedIn.emit(true)
// // Report the permission result:
// reportPermissionResult(result)
}
catch (e: HomeException) { MainActivity.showError(this, e.message.toString()) }
}
}
מריצים את האפליקציה בטלפון, פועלים לפי השלבים ומאשרים את ההרשאות. התהליך הבא אמור להופיע:

ההודעה 'טעינה' לא נעלמת, אבל זה קורה כי לא הטמענו את הקוד שקורא את המבנה והמכשירים. נעשה את זה בקטע הבא.
5. הסבר על מודל הנתונים
בממשקי ה-API של Home, מודל הנתונים מורכב מהרכיבים הבאים:
-
Structureמייצג בית שמכיל חדרים ומכשירים. -
Roomהוא חלק ממבנה ומכיל מכשירים. - אפשר להקצות מכשירים (שמוגדרים כ-
HomeDevice) למבנה (או לבית) או לחדר במבנה. - מכשירים מורכבים ממופע אחד או יותר של
DeviceType. -
DeviceTypeמורכב מ-Traitמקרים. -
Traitמורכב ממופעיAttribute(לקריאה/כתיבה), ממופעיCommand(לשליטה במאפיינים) וממופעיEvent(לקריאה או להרשמה לרשומות של שינויים קודמים). - מופעים של
Automationהם חלק ממבנה, והם משתמשים במטא-נתונים ובמכשירים של הבית כדי לבצע אוטומציה של משימות בבית.

בקטע הזה נסביר איך לפתח את קוד המקור כדי להראות איך להשתמש ב-Structure API כדי לנתח ולהציג את מבני הבית, החדרים, המכשירים וכו'.
מבנים שנקראו
העיצוב של Home APIs מבוסס על Kotlin Flows כדי להזרים את האובייקטים של מודל הנתונים (לדוגמה, Structure, HomeDevice וכן הלאה). מפתחים נרשמים ל-Flow כדי לקבל את כל האובייקטים שכלולים באובייקט (לדוגמה, Structure, Room וכן הלאה).
כדי לאחזר את כל המבנים, קוראים לפונקציה structures(), שמחזירה זרימה של מבנים. לאחר מכן, קוראים לפונקציית הרשימה בזרימה כדי לקבל את כל המבנים שהמשתמש הוא הבעלים שלהם.
// Get the a snapshot of all structures from the current homeClient
val allStructures : Set<Structure> =
homeClient.structures() // HomeObjectsFlow<Structure>
.list() // Set<Structure>
במדריך לארכיטקטורת אפליקציות מומלץ מאוד לאמץ גישה מודרנית של תכנות תגובתי כדי לשפר את זרימת הנתונים באפליקציה ואת ניהול המצב.
כך אפשר לראות איך אפליקציית הדוגמה עומדת בדרישות של סגנון כתיבת קוד תגובתי:
- מודלים של תצוגות (כמו
StructureViewModelו-DeviceViewModel, בתור מחזיק המצב) נרשמים ל-Flows מ-Home APIs SDK כדי לקבל שינויים בערכים ולשמור על המצבים העדכניים ביותר. - תצוגות (כמו
StructureViewו-DeviceView) נרשמות למודלים של תצוגות כדי לקבל את המצבים ולעבד את ממשק המשתמש כך שישקף את השינויים האלה. - כשמשתמש לוחץ על לחצן בתצוגה (לדוגמה, הלחצן 'הפעלה' של מכשיר תאורה), אירועים מפעילים את הפונקציות של מודל התצוגה, שקוראות לפונקציות של ממשקי ה-API של Home שמגיבות (לדוגמה, הפקודה
Onשל מאפייןOnOff).
בשלב 5.1.1 ב-HomeAppViewModel.kt, אנחנו נרשמים לאירועים של שינוי במבנה על ידי קריאה לפונקציה collect(). מבטלים את ההערה בקטע שבו מתבצעת סריקה של structureSet שמוחזר בתגובה מה-Structures API ומועבר ב-StructureViewModel's StateFlow. ההרשאה הזו מאפשרת לאפליקציה לעקוב אחרי שינויים במצב המבנה:
private suspend fun subscribeToStructures() {
// TODO: 5.1.1 - Subscribe the structure data changes
// // Subscribe to structures returned by the Structures API:
// homeApp.homeClient.structures().collect { structureSet ->
// val structureVMList: MutableList<StructureViewModel> = mutableListOf()
// // Store structures in container ViewModels:
// for (structure in structureSet) {
// structureVMList.add(StructureViewModel(structure))
// }
// // Store the ViewModels:
// structureVMs.emit(structureVMList)
//
// // If a structure isn't selected yet, select the first structure from the list:
// if (selectedStructureVM.value == null && structureVMList.isNotEmpty())
// selectedStructureVM.emit(structureVMList.first())
//
// }
}
ב-DevicesView.kt, האפליקציה נרשמת ל-StructureViewModel'sStateFlow, שמופעל כשנתוני המבנה משתנים, וגורם להרכבה מחדש של ממשק המשתמש. בטלו את הסימון כהערה של קוד המקור בשלב 5.1.2 כדי לרנדר את רשימת המבנים כתפריט נפתח:
val structureVMs: List<StructureViewModel> = homeAppVM.structureVMs.collectAsState().value
...
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
// TODO: 5.1.2 - Show list of structures in DropdownMenu
// for (structure in structureVMs) {
// DropdownMenuItem(
// text = { Text(structure.name) },
// onClick = {
// scope.launch { homeAppVM.selectedStructureVM.emit(structure) }
// expanded = false
// }
// )
// }
}
...
מריצים את האפליקציה שוב. כשמקישים על החץ, התפריט אמור להופיע:

ניתוח המבנה
השלב הבא הוא מעבר בין האובייקטים של הבית במבנה. אחזור החדרים מהמבנה:
val rooms: Set<Room>
rooms = structure.rooms().list()
אחר כך תוכלו לעבור בין החדרים כדי לאחזר מכשירים:
val devices: Set<HomeDevice>
devices = room.devices().list()
חשוב: במודל הנתונים של Home APIs, מבנה יכול להכיל מכשירים שלא הוקצו לחדר, לכן חשוב לכלול באפליקציה גם את המכשירים שלא הוקצו לחדר:
val devicesWithoutRooms: MutableSet<HomeDevice> = mutableSetOf()
for (device in structure.devices().list())
if (device.roomId == null)
devicesWithoutRooms.add(device)
שוב, בקוד לדוגמה הקיים, אנחנו נרשמים ל-flow כדי לקבל את הרשימה העדכנית של החדרים והמכשירים. בודקים את הקוד בשלבים 5.2.1 ו-5.2.2 בקובץ המקור StructureViewModel.kt ומבטלים סימון כהערה כדי להפעיל את המינוי לנתוני החדר:
val roomVMs : MutableStateFlow<List<RoomViewModel>>
val deviceVMs : MutableStateFlow<List<DeviceViewModel>>
val deviceVMsWithoutRooms : MutableStateFlow<List<DeviceViewModel>>
private suspend fun subscribeToRooms() {
// TODO: 5.2.1 - Subscribe the room data changes
// // Subscribe to changes on rooms:
// structure.rooms().collect { roomSet ->
// val roomVMs = mutableListOf<RoomViewModel>()
// // Store rooms in container ViewModels:
// for (room in roomSet) {
// roomVMs.add(RoomViewModel(room))
// }
// // Store the ViewModels:
// this.roomVMs.emit(roomVMs)
// }
}
private suspend fun subscribeToDevices() {
// TODO: 5.2.2 - Subscribe the device data changes in a structure
// // Subscribe to changes on devices:
// structure.devices().collect { deviceSet ->
// val deviceVMs = mutableListOf<DeviceViewModel>()
// val deviceWithoutRoomVMs = mutableListOf<DeviceViewModel>()
// // Store devices in container ViewModels:
// for (device in deviceSet) {
// val deviceVM = DeviceViewModel(device)
// deviceVMs.add(deviceVM)
// // For any device that's not in a room, additionally keep track of a separate list:
// if (device.roomId == null)
// deviceWithoutRoomVMs.add(deviceVM)
// }
// // Store the ViewModels:
// this.deviceVMs.emit(deviceVMs)
// deviceVMsWithoutRooms.emit(deviceWithoutRoomVMs)
// }
}
כדי להציג את רשימת החדרים כתפריט, מבטלים סימון כהערה בשורות 5.2.3 ו-5.2.4 בקובץ המקור DevicesView.kt:
val selectedRoomVMs: List<RoomViewModel> =
selectedStructureVM.roomVMs.collectAsState().value
...
for (roomVM in selectedRoomVMs) {
// TODO: 5.2.3 - Render the list of rooms
// RoomListItem(roomVM)
// TODO: 5.2.4 - Render the list of devices in a room
// val deviceVMsInRoom: List<DeviceViewModel> = roomVM.deviceVMs.collectAsState().value
//
// for (deviceVM in deviceVMsInRoom) {
// DeviceListItem(deviceVM, homeAppVM)
// }
}
עכשיו, אחרי שיש לכם את המכשירים, נלמד איך לעבוד איתם.

6. עבודה עם מכשירים
ממשקי ה-API של Home משתמשים באובייקט HomeDevice כדי לתעד את המכשיר והיכולות שלו. מפתחים יכולים להירשם כמנויים למאפייני מכשירים ולהשתמש בהם כדי לייצג מכשירים לבית חכם באפליקציות שלהם.
קריאת מצבי המכשיר
אובייקט HomeDevice מציג קבוצה של ערכים סטטיים, כמו שם המכשיר או מצב הקישוריות. מפתחים יכולים לאחזר את הנתונים האלה זמן קצר אחרי שהם מקבלים את המכשיר מהממשקי ה-API:
val id: String = device.id.id
val name: String = device.name
val connectivity: ConnectivityState =
device.sourceConnectivity.connectivityState
כדי לקבל את היכולות של המכשיר, צריך לאחזר את הסוגים והמאפיינים מ-HomeDevice. כדי לעשות את זה, אפשר להירשם לזרימת העבודה של סוג המכשיר באופן הבא, ולאחזר את המאפיינים מסוגי המכשירים:
device.types().collect { typeSet ->
var primaryType : DeviceType = UnknownDeviceType()
for (typeInSet in typeSet)
if (typeInSet.metadata.isPrimaryType)
primaryType = typeInSet
val traits: List<Trait> = mutableListOf()
for (trait in primaryType.traits())
if (trait.factory in myTraits)
traits.add(trait)
for (trait in traits)
parseTrait(trait, primaryType)
}
כל מכשיר מכיל סט של DeviceType נתמכים (יכולות בחבילה), שאפשר לאחזר באמצעות device.types(). סוגי המכשירים האלה מכילים מאפיינים שאפשר לאחזר באמצעות type.traits(). כל מכשיר מסמן אחד מהסוגים שלו כסוג הראשי (שאפשר לבדוק באמצעות type.metadata.isPrimaryType) שצריך לייצג באפליקציה. כדי לספק למשתמשים חוויה מלאה, מומלץ לעבור על כל הסוגים שמוחזרים ולשלב את כל המאפיינים שזמינים לכם.
אחרי שמאחזרים מאפיין, אפשר לנתח אותו באמצעות פונקציה כמו זו שבהמשך כדי לפרש את הערכים:
fun <T : Trait?> parseTrait(trait : T, type: DeviceType) {
val status : String = when (trait) {
is OnOff -> { if (trait.onOff) "On" else "Off" }
is LevelControl -> { trait.currentLevel.toString() }
is BooleanState -> {
when (type.factory) {
ContactSensorDevice -> {
if (trait.stateValue) "Closed"
else "Open"
}
else -> ...
}
}
else -> ...
}
}
חשוב לדעת: יכולים להיות הבדלים במהות של תכונה מסוימת, בהתאם לסוג המכשיר שבו היא מוצגת (כפי שאפשר לראות בBooleanState בדוגמה הקודמת). לכן, כדי להבין מה התכונות באמת מייצגות, צריך להכיר את ההקשר של כל סוג מכשיר.
כדי לאחזר את המצבים, מבטלים את הסימון כהערה בשורות 6.1.1 ו-6.1.2 בקובץ המקור DeviceViewModel.kt:
private suspend fun subscribeToType() {
// Subscribe to changes on device type, and the traits/attributes within:
device.types().collect { typeSet ->
// Container for the primary type for this device:
var primaryType : DeviceType = UnknownDeviceType()
...
// TODO: 6.1.1 - Determine the primary type for this device
// // Among all the types returned for this device, find the primary one:
// for (typeInSet in typeSet)
// if (typeInSet.metadata.isPrimaryType)
// primaryType = typeInSet
//
// // Optional: For devices with a single type that did not define a primary:
// if (primaryType is UnknownDeviceType && typeSet.size == 1)
// primaryType = typeSet.first()
// Container for list of supported traits present on the primary device type:
val supportedTraits: List<Trait> = getSupportedTraits(primaryType.traits())
...
}
fun getSupportedTraits(traits: Set<Trait>) : List<Trait> {
val supportedTraits: MutableList<Trait> = mutableListOf()
// TODO: 6.1.2 - Get only the supported traits for this device
// for (trait in traits)
// if (trait.factory in HomeApp.supportedTraits)
// supportedTraits.add(trait)
return supportedTraits
}
מבטלים את ההערה בשלב 6.1.3 ב-DeviceView.kt כדי לרנדר מאפיין OnOff, כולל השם והסטטוס שלו, כ-String:
Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
// TODO: 6.1.3 - Render controls based on the trait type
// Column (Modifier.fillMaxWidth()) {
// Text(trait.factory.toString(), fontSize = 20.sp)
// Text(DeviceViewModel.getTraitStatus(trait, type), fontSize = 16.sp)
// }
...
}
is LevelControl -> {
...
}
is BooleanState -> {
...
}
is OccupancySensing -> {
...
}
...
}
אם מריצים את האפליקציה עכשיו עם סוגי מכשירים נתמכים (לדוגמה, מכשיר Light), אמורים לראות את המצבים העדכניים של כל המכשירים.

הפעלת פקודות למכשיר
כדי להנפיק פקודות למכשירים, ממשקי ה-API של Home מספקים פונקציות נוחות באובייקטים של מאפיינים כמו trait.on() או trait.moveToLevel(...):
fun <T : Trait?> issueCommand(trait : T) {
when (trait) {
is OnOff -> {
// trait.on()
// trait.off()
}
is LevelControl -> {
// trait.moveToLevel(...)
// trait.moveToLevelWithOnOff(...)
}
}
}
טיפ: אחרי שמזהים את סוג המאפיין, אפשר להשתמש בתכונת ההשלמה האוטומטית של Android Studio כדי לראות אילו פעולות זמינות לאינטראקציה עם המאפיין.
בטלו סימון כהערה של שלב 6.2.1 ב-DeviceView.kt כדי להוסיף לאפליקציה אמצעי בקרה פונקציונליים:
Box (Modifier.padding(horizontal = 24.dp, vertical = 8.dp)) {
when (trait) {
is OnOff -> {
....
// TODO: 6.2.1 - Render controls based on the trait type
// Switch (checked = (trait.onOff == true), modifier = Modifier.align(Alignment.CenterEnd),
// onCheckedChange = { state ->
// scope.launch { if (state) trait.on() else trait.off() }
// },
// enabled = isConnected
// )
}
אם מפעילים את האפליקציה עכשיו, היא אמורה לאפשר לכם לשלוט במכשירים פיזיים אמיתיים.
אם מקישים על לחצן ההפעלה/ההפסקה של הנורה, המכשיר אמור להידלק.

מידע נוסף על שליטה במכשירים זמין במאמר שליטה במכשירים ב-Android.
7. עמלות מכשירים
ה-Commissioning API מאפשר למפתחים להוסיף מכשירים לסביבה העסקית של Google Home, ולהפוך אותם לזמינים לשליטה באמצעות ממשקי ה-API של Home. יש תמיכה רק במכשירי Matter. בקטע הזה נסביר איך להפעיל את תהליך ההגדרה של מכשירים באפליקציות.
לפני שמתחילים את החלק הזה, חשוב לוודא שהתנאים המוקדמים הבאים מתקיימים:
- רכזת Google שתומכת ב-Matter שנמצאת באותה רשת כמו טלפון Android שלכם נוספה לאפליקציית Google Home.
- יצרת פרויקט למפתחים ב-Google Home Developer Console עם ה-VID
0xFFF1וה-PID0x8000.
אם יש לכם מכשיר פיזי בתקן Matter עם קוד QR להפעלה, אתם יכולים לדלג אל הפעלת API להפעלה. אחרת, אפשר להמשיך לקטע הבא שבו נסביר איך אפשר להשתמש באפליקציית Matter Virtual Device (MVD) כדי ליצור מכשירים וירטואליים שניתן לקבל עליהם עמלה.
אופציונלי: הכנת מכשיר שאפשר להוסיף לרשת Matter
הדרך הכי פשוטה להכין מכשיר שאפשר להפעיל בו Matter היא באמצעות מכשיר מדומה שמופיע באפליקציית Matter Virtual Device (MVD).
אחרי שמתקינים את MVD ומגדירים את חומת האש, מריצים את MVD:

יוצרים מכשיר OnOff. שימו לב שהיא עדיין לא הופעלה – תפעילו אותה בהמשך ב-Codelab הזה.

הפעלת Commissioning API
ממשק ה-API של ההפעלה פועל מחוץ לפעילות של האפליקציה, ולכן צריך לטפל בהפעלה באופן שונה מממשקי ה-API האחרים של Home. כדי להכין את האפליקציה להפעלה, צריך שני משתנים.
משתנה אחד הוא ActivityResultLauncher, שמשמש לשליחת כוונת ההפעלה ולניהול הקריאה החוזרת של התוצאה. המשתנה השני הוא CommissioningResult, שהוא האובייקט שמשמש לאחסון תוצאת ההפעלה. בדוגמה הבאה אפשר לראות איך להגדיר הפעלה:
var launcher: ActivityResultLauncher<IntentSenderRequest>
lateinit var commissioningResult: CommissioningResult?
launcher = activity.registerForActivityResult(StartIntentSenderForResult()) { result ->
try {
commissioningResult = CommissioningResult.fromIntentSenderResult(
result.resultCode, result.data)
} catch (exception: ApiException) {
// Catch any issues
}
}
אחרי שמגדירים את תהליך ההפעלה, יוצרים את כוונת ההפעלה ומפעילים אותה באמצעות מרכז ההפעלה שיצרנו בדוגמה הקודמת. מומלץ למקם את ה-intent ואת ה-launcher בפונקציה ייעודית כמו זו שמופיעה בהמשך. אפשר לקשר פונקציה ייעודית לרכיב בממשק המשתמש (כמו הלחצן +הוספת מכשיר) ולהפעיל אותה על סמך בקשת המשתמש:
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
scope.launch {
// Create a commissioning request to store the device in Google's Fabric:
val request = CommissioningRequest.builder()
.setStoreToGoogleFabric(true)
.setOnboardingPayload(payload)
.build()
// Initialize client and sender for commissioning intent:
val client: CommissioningClient = Matter.getCommissioningClient(context)
val sender: IntentSender = client.commissionDevice(request).await()
// Launch the commissioning intent on the launcher:
launcher.launch(IntentSenderRequest.Builder(sender).build())
}
}
לבטל סימון כהערה משלב 7.1.1 ב-CommissioningManager.kt כדי להפעיל את היכולת להקצאת הרשאות ולגרום ללחצן +הוספת מכשיר לפעול באפליקציית הדוגמה.
// Called by +Add Device button in DeviceView.kt
fun requestCommissioning() {
// Retrieve the onboarding payload used when commissioning devices:
val payload = activity.intent?.getStringExtra(Matter.EXTRA_ONBOARDING_PAYLOAD)
// TODO: 7.1.1 - Launch the commissioning intent
// scope.launch {
// // Create a commissioning request to store the device in Google's Fabric:
// val request = CommissioningRequest.builder()
// .setStoreToGoogleFabric(true)
// .setOnboardingPayload(payload)
// .build()
// // Initialize client and sender for commissioning intent:
// val client: CommissioningClient = Matter.getCommissioningClient(context)
// val sender: IntentSender = client.commissionDevice(request).await()
// // Launch the commissioning intent on the launcher:
// launcher.launch(IntentSenderRequest.Builder(sender).build())
// }
}
הפעלת הפונקציה הזו אמורה להתחיל את תהליך ההפעלה, שבו יוצג מסך שדומה לצילום המסך הבא:

הסבר על תהליך ההפעלה
תהליך ההפעלה כולל סדרה של מסכים שמנחים את המשתמש בהוספת מכשיר לחשבון Google שלו:

למשתמשים יוצג סורק קודי QR שבו הם יכולים להשתמש כדי לסרוק את קודי ה-QR ממכשירי Matter. לאחר מכן יוצג הסכם המשתמש, יתבצע חיפוש רחב של מכשירים והפעלתם, ויינתן שם למכשיר. אחרי שהתהליך יסתיים, המיקוד יחזור לאפליקציה, ותוצאת ההפעלה תועבר בפונקציית קריאה חוזרת שכתבנו בקטע הקודם.
אחד היתרונות של ממשקי ה-API להפעלת מכשירים הוא שזרימת חוויית המשתמש מטופלת על ידי ה-SDK, כך שמפתחים יכולים להתחיל להשתמש בהם במהירות. בנוסף, המשתמשים מקבלים חוויה עקבית כשהם מוסיפים מכשירים באפליקציות שונות.
מידע נוסף על Commissioning API זמין במאמר Commissioning API ב-Android.
8. מעולה!
מעולה! יצרתם בהצלחה אפליקציית Android באמצעות ממשקי Google Home API. במהלך ה-codelab הזה, למדתם על הרשאות, מכשירים, מבנים וממשקי API להפעלה. ב-codelab הבא, Create advanced automations using the Home APIs on Android Codelab (יצירת אוטומציות מתקדמות באמצעות ממשקי ה-API של Home ב-Android Codelab), נסביר על ממשקי ה-API של Automation ו-חיפוש רחב, ונשלים את האפליקציה.
אנחנו מקווים שתיהנו מפיתוח אפליקציות ששולטות במכשירים בצורה יצירתית בסביבה העסקית של Google Home.
השלבים הבאים
- כדי להמשיך לחלק הבא בתהליך הלמידה של Home APIs ב-Android, צריך להשלים את ה-codelab השני בסדרה הזו: יצירת אוטומציות מתקדמות באמצעות Home APIs ב-Android.
- אתם יכולים לשלוח לנו המלצות או לדווח על בעיות דרך Issue Tracker בנושא התמיכה בבית חכם.