אפשר לגשת לממשקי ה-API של המכשירים דרך Home APIs ל-Android. מייבאים את החבילות האלה לאפליקציה:
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
כדי להשתמש בסוגי מכשירים או בתכונות ספציפיים עם ממשקי ה-API של המכשירים, צריך לייבא אותם בנפרד.
לדוגמה, כדי להשתמש בתכונה Matter On/Off ובסוג המכשיר On/Off Plug-in Unit, מייבאים את החבילות הבאות לאפליקציה:
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice
מידע נוסף זמין במאמר מודל הנתונים ב-Android.
טיפול בשגיאות
כל שיטה ב-Home APIs יכולה להפעיל
HomeException, לכן מומלץ להשתמש בבלוק try-catch כדי לתפוס את HomeException בכל הקריאות.
כשמטפלים ב-HomeException, צריך לבדוק את השדות
error.code ו-
error.message כדי להבין מה השתבש. יכול להיות שיהיו גם קודי שגיאות משניים, אז צריך להפעיל את השיטה
getSubErrorCodes() ולבדוק את התוצאה.
כל חריגה שלא תטופל תגרום לקריסת האפליקציה.
מידע נוסף מופיע במאמר טיפול בשגיאות.
דוגמה לכך מופיעה במאמר שליחת פקודה למכשיר.
שיחות לדוגמה
קבלת רשימה של מכשירים
אחרי שיש לכם הפניה למופע של Structure, קריאה ל-devices() מחזירה Flow של מכשירים שנגישים לכם מהמבנה הזה:
// Get a flow of all devices accessible to the user val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices() // Calling list() on a HomeObjectsFlow returns the first Set of elements. val allDevices: Set<HomeDevice> = allDevicesFlow.list()
משם אתם יכולים לגשת למצבים של כל מכשיר ולשלוח פקודות למכשירים.
בגרסה 1.8 של ממשקי ה-API של Home, אתם יכולים להגדיר שה-API ייצג כל מכשיר עם כמה חלקים כמכשיר אחד. כדי לעשות את זה, מגדירים את הפרמטר enableMultipartDevices של השיטה devices() לערך true. מידע נוסף זמין במאמר מכשירים מרובי-חלקים ב-Android.
קריאת מצב המכשיר
דוגמה לבדיקת המאפיין OnOff מהתכונה On/Off של המכשיר. באמצעות מודל הנתונים של התכונות ב-Home APIs, שבו התכונה הזו מזוהה בתור OnOff, אתם יכולים לאחזר את נתוני התכונות דרך המחלקה standardTraits של סוג המכשיר:
// Assuming we have a device. val deviceFlow = home.devices().itemFlow(myDeviceId) val device = deviceFlow.first() // Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger // on the specific trait changes and not the whole type. val onOffTraitFlow: Flow<OnOff?> = device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged() val onOffTrait: OnOff = onOffTraitFlow.first()!!
distinctUntilChanged
למידע נוסף על פונקציית הזרימה של Kotlin.
ביטול התוקף של מצב במינוי למאפיין
ממשק TraitStateInvalidation מאפשר לבטל מצב שאוחזר באמצעות מינויים למכשיר היעד, במקרים שבהם המצב לא מדווח בצורה נכונה.
דוגמאות למקרים שבהם יכול להיות שהמצב לא ידווח בצורה נכונה:
שימוש במאפיינים בתכונות Matter עם איכות "C"
או בגלל הטמעה במכשיר שגורמת לבעיה באופן בלתי צפוי.
ה-API הזה מנפיק קריאה מאולצת של מצב המאפיין הנוכחי ומחזיר את התוצאה דרך תהליכי המאפיינים הקיימים.
מקבלים את המאפיין, ואז מריצים forceRead על המאפיין:
val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()
איך מקבלים רשימה של תכונות לפי סוג מכשיר
סוגי המכשירים צריכים לשמש כנקודת כניסה לקריאת תכונות, כי הם מפרקים מכשיר לחלקים הפונקציונליים שלו (כמו נקודות קצה ב-Matter).
הם גם מביאים בחשבון התנגשויות בין תכונות במקרה שלמכשיר יש שני סוגי מכשירים, שלשניהם יכולה להיות אותה תכונה. לדוגמה, אם מכשיר הוא גם רמקול וגם נורה עם עמעם, יהיו לו שתי תכונות של הפעלה/כיבוי ושתי תכונות של בקרת רמה.
כדי לקבל את רשימת התכונות הזמינות לסוג המכשיר "תאורה עם עמעם":
// Get all types available on this device. Requires the types to be part of the registry during // SDK initialization. val typesFlow: Flow<Set<DeviceType>> = device.types() // Get a snapshot of all types. val types: Set<DeviceType> = typesFlow.first() // Get the DimmableLightDevice instance from the set of types. val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull() // Get all traits in the type + traits registered val allTraits: Set<Trait> = dimmableLightDevice!!.traits()
סוג אחר של התנגשות בין תכונות יכול להתרחש כשלמכשיר יש שתי תכונות עם אותו שם. לדוגמה, onOff יכול להתייחס למופע של המאפיין הסטנדרטי OnOff, או למופע של המאפיין OnOff שהוגדר על ידי היצרן. כדי למנוע אי-בהירות לגבי התכונה הרצויה, צריך להוסיף קידומת של מרחב שמות מתאים למופע של Trait שמופנה דרך מכשיר. למאפיינים רגילים, כלומר כאלה שמקבילים לאשכולות הרגילים של Matter, צריך להשתמש ב-standardTraits. למאפיינים של Google, משתמשים ב-googleTraits:
// Accessing standard traits on the type. val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl
כדי לגשת לתכונה ספציפית ליצרן, צריך להפנות אליה ישירות:
// Accessing a custom trait on the type. val customTrait = dimmableLightDevice.trait(MyCustomTrait)
קבלת רשימה של מכשירים עם תכונה ספציפית
אפשר להשתמש בפונקציה filter ב-Kotlin כדי לחדד עוד יותר את הקריאות ל-API. לדוגמה, כדי לקבל רשימה של מכשירים בבית שיש להם את התכונה On/Off:
// Get all devices that support OnOff val onOffDevices: Flow<List<HomeDevice>> = home.devices().map { devices -> devices.filter { it.has(OnOff) } }
בממשק Trait מופיעה רשימה מלאה של התכונות שזמינות ב-Home APIs.
קבלת רשימה של מכשירים עם סוגי מכשירים דומים
כדי לקבל רשימה של מכשירים שמייצגים את כל האורות בבית:
// Get a list of devices with similar device types (lights) val lightDevices = home.devices().map { devices -> devices.filter { it.has(DimmableLightDevice) || it.has(OnOffLightDevice) || it.has(ColorTemperatureLightDevice) || it.has(ExtendedColorLightDevice) } }
יש כמה סוגי מכשירים ב-Home APIs שיכולים לייצג סוג מכשיר ליבה. לדוגמה, אין סוג מכשיר שנקרא "תאורה". במקום זאת, יש ארבעה סוגי מכשירים שונים שיכולים לייצג נורה, כמו בדוגמה הקודמת. לכן, כדי לקבל תצוגה מקיפה של סוג מכשיר ברמה גבוהה יותר בבית, צריך לכלול כמה סוגי מכשירים בתהליכים מסוננים.
רשימה מלאה של סוגי המכשירים שזמינים ב-Home APIs מופיעה בממשק DeviceType.
איך למצוא את מזהה הספק או מזהה המוצר של מכשיר
המאפיין BasicInformation כולל מידע כמו מזהה הספק, מזהה המוצר, שם המוצר והמספר הסידורי של המכשיר:
// Get device basic information. All general information traits are on the RootNodeDevice type. val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!! println("vendorName ${basicInformation.vendorName}") println("vendorId ${basicInformation.vendorId}") println("productId ${basicInformation.productId}")
זיהוי מכשירים ב-Cloud-to-cloud ליצרני מכשירים
אם אתם יצרני מכשירים ומייצרים מכשירי Cloud-to-cloud, כדי לזהות את מכשירי Cloud-to-cloud באמצעות התכונה BasicInformation, אתם יכולים לכלול את שדות המחרוזת האלה בתגובת SYNC שלהם:
מזהה הספק שהונפק על ידי Connectivity Standards Alliance (Alliance):
"matterOriginalVendorId": "0xfff1",מזהה מוצר שמזהה באופן ייחודי מוצר של ספק:
"matterOriginalProductId": "0x1234",מזהה ייחודי של המכשיר, שנוצר באופן ספציפי ליצרן:
"matterUniqueId": "matter-device-id",
כשמזינים את שדות המחרוזת האלה, צריך להשתמש בMatter
מזהי הספק והמוצר, אם יש כאלה. אם אתם לא חברים ב-Alliance ולא הוקצו לכם המזהים האלה, אתם יכולים להשאיר את השדות matterOriginalVendorId ו-matterOriginalProductId ריקים ולציין את ה-matterUniqueId כמזהה.
תגובת ה-SYNC לדוגמה מראה את השימוש בשדות האלה:
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"agentUserId": "1836.15267389",
"devices": [
{
"id": "456",
"type": "action.devices.types.LIGHT",
"traits": [
"action.devices.traits.OnOff",
"action.devices.traits.Brightness",
"action.devices.traits.ColorSetting",
],
"willReportState": true,
"deviceInfo": { ... },
"matterOriginalVendorId": "0xfff1",
"matterOriginalProductId": "0x1234",
"matterUniqueId": "matter-device-id",
"otherDeviceIds": [
{
"deviceId": "local-device-id",
}
]
}
]
}
}
מידע נוסף זמין במאמרי העזרה של Cloud-to-cloud SYNC.
מטא-נתונים של מכשירים ותכונות
למכשירים ולתכונות ב-Home APIs יש מטא-נתונים שמשויכים אליהם, שיכולים לעזור בניהול חוויית המשתמש באפליקציה.
כל תכונה ב-Home APIs מכילה מאפיין
sourceConnectivity
שכולל מידע על סטטוס החיבור של התכונה ועל המיקום שלה (ניתוב מקומי או מרחוק).
קבלת הסוג הראשי של המכשיר
יכול להיות שמכשירים מסוימים יציגו כמה סוגי מכשירים דרך ממשקי ה-Home API. כדי לוודא שהמשתמשים רואים באפליקציה את האפשרויות שמתאימות למכשירים שלהם (כמו שליטה במכשיר והצעות לאוטומציות), כדאי לבדוק מה סוג המכשיר הראשי של המכשיר.
קודם כל, מקבלים את סוגי המכשירים באמצעות type(), ואז קובעים את הסוגים הראשיים:
val types = device.types().first() val primaryTypes = types.filter { it.metadata.isPrimaryType }
איך בודקים אם תכונה מסוימת מחוברת לאינטרנט
משתמשים ב-method connectivityState() כדי לבדוק את הקישוריות של התכונה:
val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState
יכול להיות שחלק מהתכונות, בדרך כלל תכונות של Google smart home, יוצגו במצב אופליין אם למכשיר אין חיבור לאינטרנט. הסיבה לכך היא שהתכונות האלה מבוססות-ענן ואין להן ניתוב מקומי.
בדיקת החיבור של המכשיר
הקישוריות של מכשיר נבדקת בפועל ברמת סוג המכשיר, כי חלק מהמכשירים תומכים בכמה סוגי מכשירים. המצב שמוחזר הוא שילוב של מצבי הקישוריות של כל התכונות במכשיר הזה.
val lightConnectivity = dimmableLightDevice.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()
בדיקת הניתוב ברשת של מאפיין
המיקום של התכונה זמין גם ב-Home APIs. השדה dataSourceLocality מציין אם התכונה מנותבת מרחוק (דרך הענן), באופן מקומי (דרך רכזת מקומית) או בין עמיתים (ישירות ממכשיר למכשיר, ללא רכזת).
ערך המיקום הלא ידוע UNSPECIFIED יכול להופיע, למשל, כשאפליקציה מופעלת ועדיין לא הגיעה לרכזת או לשרת לקישוריות המכשיר. אי אפשר להגיע למכשירים האלה, והם לא יגיבו לבקשות לאינטראקציה מפקודות או מאירועים. הלקוח צריך להחליט איך לטפל במכשירים כאלה.
val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality
בדיקת הניתוב ברשת של מכשיר
בדומה לקישוריות, המיקום נבדק ברמת סוג המכשיר. המצב שמוחזר הוא שילוב של המיקום של כל התכונות במכשיר הזה.
val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality
מצב של MIXED יכול להתרחש בתרחיש דומה לזה של קישוריות PARTIALLY_ONLINE: חלק מהתכונות מבוססות-ענן ואחרות מקומיות.
שינוי השם של מכשיר
כדי לשנות את השם של מכשיר, מבצעים קריאה ל-setName():
mixerDevice.setName("Grendel")
שמות ארוכים יותר ממגבלת 60 מיקומי התווים (code point) של Unicode ייחתכו, ולא יוצגו שגיאות. המפתחים אחראים לטיפול בשמות ארוכים, ויכולים, למשל, להחליט אם הם רוצים להודיע למשתמשים שהשמות ייחתכו.
בדיקת החברות בקבוצה של מכשיר
מכשיר פיזי יכול להשתייך לקבוצת מכשירים אחת או יותר. כדי לראות לאילו קבוצות המכשיר שייך, בודקים את המאפיין GroupMembership במכשיר:
val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
println("HomeAPI", "Device belongs to group: $groupId")
}
לעומת זאת, אפשר לראות את כל המכשירים של החברים ששייכים ל-DeviceGroup על ידי קריאה לתהליך devices() ב-DeviceGroup:
group.devices(enableMultipartDevices = true).collect { members ->
println("HomeAPI", "Group contains ${members.size} devices")
}
כדי לבדוק את סוגי המכשירים שנתמכים על ידי DeviceGroup ולשלוח פקודות לקבוצה כישות אחת, ראו שליטה בקבוצת מכשירים.