גישה למכשירים ולמטא-נתונים של מכשירים ב-Android

אפשר לגשת לממשקי API של מכשירים דרך ממשקי ה-API של Home ל-Android. מייבאים את החבילות האלה לאפליקציה:

import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id

כדי להשתמש בסוגים או במאפיינים ספציפיים של מכשירים עם ממשקי Device 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, בודקים את השדות code ו-message כדי להבין מה השתבש.

חריגים שלא טופלו יגרמו לקריסת האפליקציה.

מידע נוסף זמין במאמר בנושא טיפול בשגיאות.

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

דוגמאות לשיחות

קבלת רשימת מכשירים

אם המבנה זמין, קריאה ל-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()

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

קריאת סטטוס המכשיר

נבחן עכשיו דוגמה לבדיקת המאפיין OnOff ממאפיין ההפעלה/ההשבתה של המכשיר. באמצעות מודל הנתונים של מאפייני 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()!!

מידע נוסף על פונקציית Kotlin flow זמין במאמר distinctUntilChanged.

ביטול תוקף של מצב במינוי לתכונה

ממשק TraitStateInvalidation מאפשר לבטל מצב שאוחזר באמצעות מינויים למכשיר היעד במקרים שבהם המצב לא מדווח בצורה נכונה. דוגמאות למקרים שבהם יכול להיות שהמצב לא ידווח בצורה נכונה: שימוש במאפיינים בתכונות Matter עם איכות 'C' או בגלל הטמעה במכשיר שגורמת לבעיה באופן בלתי צפוי.

ה-API הזה מבצע קריאה מאולצת של המצב הנוכחי של התכונה ומחזיר את התוצאה באמצעות תהליכי העבודה הקיימים של התכונה.

מקבלים את המאפיין, ואז מריצים forceRead על המאפיין:

val generalDiagnosticsTrait = device.trait(GeneralDiagnostics).first()
generalDiagnosticsTrait.forceRead()

קבלת רשימה של מאפיינים של סוגי מכשירים

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

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

כדי לקבל את רשימת המאפיינים הזמינים לסוג המכשיר Dimmable Light (נורת דימר):

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

רשימה מלאה של המאפיינים שזמינים בממשקי ה-API של Home מופיעה בממשק Trait.

קבלת רשימה של מכשירים עם סוגי מכשירים דומים

כדי לקבל רשימה של מכשירים שמייצגים את כל האורות בבית:

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

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

DeviceType כאן אפשר לראות את הרשימה המלאה של סוגי המכשירים שזמינים בממשקי ה-API של Home.

איך מקבלים את מזהה הספק או מזהה המוצר של מכשיר

מאפיין 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 באמצעות מאפיין BasicInformation, אתם יכולים לכלול את שדות המחרוזת האלה בתגובת SYNC שלהם:

  • מזהה הספק שהונפק על ידי Connectivity Standards Alliance ‏ (CSA): "matterOriginalVendorId": "0xfff1",

  • מזהה מוצר שמזהה באופן ייחודי מוצר של ספק: "matterOriginalProductId": "0x1234",

  • מזהה ייחודי של המכשיר, שנוצר באופן ספציפי ליצרן: "matterUniqueId": "matter-device-id",

כשמזינים את שדות המחרוזת האלה, משתמשים במזהי הספק והמוצר אם יש לכם אותם.Matter אם אתם לא חברים ב-CSA ולא הוקצו לכם המזהים האלה, אתם יכולים להשאיר את השדות 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.

מטא-נתונים של מכשירים ומאפיינים

למכשירים ולמאפיינים בממשקי ה-API של Home יש מטא-נתונים שמשויכים אליהם, שיכולים לעזור בניהול חוויית המשתמש באפליקציה.

כל מאפיין בממשקי ה-API של Home מכיל מאפיין sourceConnectivity, שכולל מידע על הסטטוס אונליין של המאפיין ועל המיקום שלו (ניתוב מקומי או מרחוק).

קבלת הסוג הראשי של מכשיר

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

קודם כול, מקבלים את סוגי המכשירים באמצעות type(), ואז קובעים את הסוגים העיקריים:

val types = device.types().first()
val primaryTypes = types.filter { it.metadata.isPrimaryType }

איך בודקים אם תכונה מסוימת זמינה באינטרנט

כדי לבדוק את הקישוריות של מאפיין, משתמשים בשיטה connectivityState():

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

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

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

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

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

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

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

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

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

val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality

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

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

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

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

שינוי השם של מכשיר

מתקשרים אל שיטת setName() כדי לשנות את השם של מכשיר:

mixerDevice.setName("Grendel")

שמות שיכילו יותר מ-60 תווים יחתכו, ולא יוצגו שגיאות. המפתחים אחראים לטיפול בשמות ארוכים. לדוגמה, הם יכולים להחליט אם הם רוצים להודיע למשתמשים שהשמות יקוצרו.

רשימת ממשקי API

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

API תיאור
devices() לקבל את כל המכשירים בכל המבנים בחשבון Google. הפונקציה מחזירה HomeObjectsFlow שמספק אפשרויות נוספות לאחזור ולסינון.

אחרי שיהיה לכם HomeDevice, תוכלו לגשת דרכו לממשקי ה-API הבאים:

API תיאור
allCandidates() מחזירה את כל המועמדים לאוטומציה עבור המכשיר והצאצאים שלו.
candidates() מחזירה את כל המועמדים לאוטומציה של המכשיר.
connectivityStateChanged הפעם האחרונה שבה השתנה מצב המכשיר.
events(event) קבלת רצף של אירוע ספציפי.
events(trait) קבלת רצף של כל האירועים לפי המאפיין הזה.
events(traits) מקבלים רצף של כל האירועים לפי המאפיינים האלה.
getSourceConnectivity(trait) אחזור מטא-נתונים של מאפיין מסוים. הפונקציה מחזירה SourceConnectivity.
has(trait) בודקים אם המכשיר תומך בתכונה המבוקשת הנוכחית.
has(type) אם המכשיר תומך בסוג שצוין.
id המזהה הייחודי של המכשיר במערכת.
isInRoom אם המכשיר נמצא בחדר.
isInStructure אם המכשיר נמצא במבנה.
isMatterDevice אם המכשיר מגובה על ידי Matter.
name השם שהמשתמש נתן למכשיר.
room() החדר שהמכשיר מוקצה לו. הפונקציה מחזירה Room.
roomId המזהה של החדר שהמכשיר מוקצה לו. הפונקציה מחזירה את הערך Id.
sourceConnectivity קישוריות המקור של המכשיר, שמייצגת מצבי קישוריות מצטברים ומיקום ברשת של מאפייני המכשיר.
structure() המבנה שהמכשיר משויך אליו. הפונקציה מחזירה Structure.
structureId המזהה של המבנה שהמכשיר משויך אליו. הפונקציה מחזירה את הערך Id.
type(type) מקבלים את הגדרת הסוג עם המאפיינים המאוכלסים (אם זמינים) לגישה ישירה. הפונקציה תמיד מחזירה תמונת מצב עדכנית של ה-traits.
types() מקבלים רשימה של כל הסוגים שזמינים במכשיר.