אפשר לגשת לממשקי API של מכשירים דרך ממשקי ה-API של Home ל-iOS. מייבאים את החבילות הבאות לאפליקציה:
import GoogleHomeSDK
import GoogleHomeTypes
מידע נוסף זמין במאמר בנושא מודל נתונים ב-iOS.
טיפול בשגיאות
חלק מהשיטות ב-Home APIs מחזירות HomeError, ולכן מומלץ להשתמש בבלוק do-catch כדי לזהות HomeError בקריאות האלה.
כשמטפלים ב-HomeError, בודקים את השדות code ו-message
כדי לברר מה השתבש.
שגיאות שלא טופלו יגרמו לקריסת האפליקציה.
מידע נוסף מופיע במאמר בנושא טיפול בשגיאות.
דוגמאות לשיחות
הורדה של רשימת מכשירים
בעזרת הפניה לאובייקט Home, מפעילים את devices() כדי לקבל את Query של המכשירים הנגישים.
קוראים לשיטה Query של batched(), שפולטת Set שמשקף את המצב הנוכחי של הבית בכל שינוי במטא-נתונים של המכשיר. אפשר גם להתקשר למספר Query.list() כדי לקבל תמונת מצב של המכשירים הזמינים. זוהי שיטה נוחה להירשמה לסטרים batched() ולהחזרת הערך הראשון שמוחזר.
Query.stream()
יוצר זרם שפולט ערכים חדשים בשינויים במטא-נתונים של המכשיר, כמו
השם, החדר או המבנה שלו. באופן פנימי, נעשה שימוש ב-batched() והמאפיינים שמשתנים מועברים בלבד.
// Get a list of all devices accessible to the user let homeDevices = try await self.home.devices().list()
משם אפשר לגשת למצבים של כל מכשיר ולשלוח פקודות למכשירים.
בגרסה 1.8 של Home APIs, יש אפשרות להגדיר את הפרמטר enableMultipartDevices של השיטה devices() לערך true כדי שממשק ה-API ייצג כל מכשיר מרובה חלקים כמכשיר יחיד. מידע נוסף זמין במאמר בנושא מכשירים מרובי חלקים ב-iOS.
קבלת סוגי המכשירים
כדי לקבל את סוגי המכשירים שמשויכים למכשיר, קוראים את המאפיין types של המכשיר, שמחזיר DeviceTypeController.
מתקשרים אל DeviceTypeController.subscribe(_:) כדי להירשם לעדכונים לגבי סוג מכשיר מסוים:
let devices = try await self.home.devices().list() if let device = devices.first(where: { $0.id == myDeviceId }) { var receivedUpdate1 = false var receivedUpdate2 = false device.types.subscribe(OnOffLightDeviceType.self) .assertNoFailure() .sink { device in if !receivedUpdate1 { receivedUpdate1 = true Task { try await device.matterTraits.onOffTrait?.on() } return } if !receivedUpdate2 { receivedUpdate2 = true return } fatalError("Received unexpected update") } }
אם המכשיר לא תומך בסוג המכשיר שצוין, הוא מחזיר Empty
Publisher שמושלם באופן מיידי.
אם המכשיר תומך בסוג מכשיר ספציפי, אפשר לקבל את הטיפול בסוג הזה על ידי קריאה ל-get():
if let device = devices.first(where: { $0.id == myDeviceId }) { let _ = await device.types.get(OnOffLightDeviceType.self) }
אם המכשיר לא תומך בסוג שצוין, הפונקציה מחזירה nil.
התקשר אל
DeviceTypeController.subscribeAll()
כדי לקבל Publisher של
DeviceTypeCollection.
המחלקות האלה מאפשרות לבדוק אם המכשיר הוא מסוג מסוים:
if let device = devices.first(where: { $0.id == myDeviceId }) { device.types.subscribeAll() .assertNoFailure() .sink { types in let lightDeviceType = types[OnOffLightDeviceType.self] let fanDeviceType = types[FanDeviceType.self] } }
קבלת מאפיין של סוג המכשיר
סוגי המכשירים הם נקודת הכניסה לקריאת המאפיינים, כי הם מפרקים מכשיר לחלקים הפונקציונליים שלו (כמו נקודות קצה ב-Matter).
הם גם מתחשבים בהתנגשויות של מאפיינים במקרה של מכשיר עם שני סוגי מכשירים, שלשניהם יכול להיות אותו מאפיין. לדוגמה, אם מכשיר הוא גם רמקול וגם מנורה עם אפשרות לעמעום, הוא יכלול שתי תכונות של הפעלה/השבתה ושתי תכונות של שליטה ברמה.
סוג אחר של התנגשות מאפיינים יכול להתרחש כשבמכשיר יש שני מאפיינים עם אותו שם. לדוגמה, onOff יכול להתייחס למופע של מאפיין OnOff רגיל, או למופע של מאפיין OnOff שהוגדר על ידי היצרן. כדי למנוע אי בהירות לגבי המאפיין הרצוי, צריך להפנות למאפיין דרך אחת משתי קולקציות המאפיינים בכל סוג מכשיר.
כדי להשתמש בתכונות רגילות, כלומר בתכונות שדומות לאשכולות רגילים של Matter, משתמשים ב-matterTraits. לדוגמה, כדי לקבל מאפיין ספציפי לסוג המכשיר Dimmable Light (אור ניתן לעמעום):
if let dimmableLightDeviceType = await device.types.get(DimmableLightDeviceType.self) { // Accessing standard trait on the type. let levelControlTrait = dimmableLightDeviceType.matterTraits.levelControlTrait.self }
למאפיינים של Google, משתמשים ב-googleTraits:
if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) { // Accessing Google trait on the type. let doorbellPressTrait = doorbellDeviceType.traits[Google.DoorbellPressTrait.self] }
כדי לגשת לתכונה ספציפית של יצרן, צריך להפנות אליה דרך המאפיין traits
property, אבל להוסיף לפניו את שם החבילה של היצרן:
let deviceType = await device1?.types.get(OnOffLightDeviceType.self) // Accessing custom trait on the type. if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] { let rpmVal = spinnerTrait.attributes.rpm }
קריאת סטטוס המכשיר
בדוגמה הזו אפשר לראות איך בודקים את המאפיין OnOff ממאפיין ההפעלה/ההשבתה של המכשיר:
let lightDevices = devices.filter { $0.types.contains(OnOffLightDeviceType.self) } let light1 = lightDevices.first let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self) if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait { let onOffVal = onOffTrait.attributes.onOff }
קבלת רשימה של מכשירים עם תכונה ספציפית
כדי לקבל רשימה של מכשירים עם מאפיין ספציפי, צריך לבצע איטרציה על המכשירים, על סוגי המכשירים של כל מכשיר ועל המאפיינים של כל סוג מכשיר. לדוגמה, כדי לקבל רשימה של מכשירים בבית שיש להם את המאפיין On/Off (הפעלה/הפסקה):
// Get all light devices that support levelControl var levelControlDevices: [HomeDevice] = [] let allDevices = try await home.devices().list() for device in allDevices { if let deviceType = await device.types.get(OnOffLightDeviceType.self) { if deviceType.traits.contains(Matter.LevelControlTrait.self) { levelControlDevices.append(device) } } }
רשימה מלאה של המאפיינים שזמינים בממשקי ה-API של Home מופיעה במאמר מדד המאפיינים ב-iOS.
קבלת רשימה של מכשירים עם סוגי מכשירים דומים
כדי לקבל רשימה של מכשירים שמייצגים את כל האורות בבית:
// Get a list of devices with similar device types (lights) let lightDevices = try await self.home.devices().list().compactMap { $0.types.contains(DimmableLightDeviceType.self) || $0.types.contains(OnOffLightDeviceType.self) || $0.types.contains(ColorTemperatureLightDeviceType.self) || $0.types.contains(ExtendedColorLightDeviceType.self) }
בממשקי ה-API של Home יש כמה סוגי מכשירים שיכולים לייצג סוג מכשיר ליבה. לדוגמה, אין סוג מכשיר 'מנורה'. במקום זאת, יש ארבעה סוגים שונים של מכשירים שיכולים לייצג אור, כמו בדוגמה הקודמת. לכן, כדי לקבל תצוגה מקיפה של מכשיר מסוג ברמה גבוהה יותר בבית, צריך לכלול כמה סוגים של מכשירים.
כאן מופיעה רשימה מלאה של סוגי המכשירים והתכונות שלהם שזמינים בממשקי ה-API של Home.
איך מקבלים את שם הספק, מזהה הספק או מזהה המוצר של מכשיר
מאפיין BasicInformationTrait
כולל מידע כמו מזהה ספק, מזהה מוצר, שם מוצר והמספר הסידורי של המכשיר:
guard let vendorName = basicInfoTrait.attributes.vendorName else { fatalError("Failed to get vendorName") } guard let vendorID = basicInfoTrait.attributes.vendorID else { fatalError("Failed to get vendorID") } guard let productID = basicInfoTrait.attributes.productID else { fatalError("Failed to get productID") }
זיהוי מכשירים בענן ליצרני מכשירים
אם אתם יצרני מכשירים ומייצרים מכשירי 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.
מטא-נתונים של מכשירים ומאפיינים
למכשירים ולמאפיינים בממשקי ה-API של Home יש מטא-נתונים שמשויכים אליהם, שיכולים לעזור בניהול חוויית המשתמש באפליקציה.
כל מאפיין בממשקי ה-API של Home מכיל מאפיין sourceConnectivity, שכולל מידע על הסטטוס אונליין של המאפיין ועל המיקום שלו (ניתוב מקומי או מרחוק).
קבלת הסוג הראשי של מכשיר
יכול להיות שבמכשירים מסוימים יוצגו כמה סוגים של מכשירים דרך ממשקי ה-API של Home. כדי לוודא שהמשתמשים יראו באפליקציה את האפשרויות המתאימות למכשירים שלהם (כמו שליטה במכשיר והצעות לאוטומציות), כדאי לבדוק אם סוג המכשיר הוא הסוג העיקרי של המכשיר.
if let deviceType = await device?.types.get(HumiditySensorDeviceType.self) { if deviceType.metadata.isPrimaryType { print("Humidity Sensor is the primary type on this device.") } else { print("Humidity Sensor isn't the primary type on this device.") } }
איך בודקים אם מאפיין מסוים מוצג באינטרנט
כדי לבדוק את הקישוריות של מאפיין, קוראים את המאפיין connectivityState:
let levelControlConnectivity = levelControlTrait.metadata.sourceConnectivity .connectivityState
חלק מהמאפיינים, בדרך כלל מאפייני Google smart home, עשויים להופיע במצב אופליין אם למכשיר אין קישוריות לאינטרנט. הסיבה לכך היא שהתכונות האלה מבוססות על ענן ואין להן ניתוב מקומי.
בדיקת החיבור של מכשיר
הקישוריות של מכשיר נבדקת למעשה ברמת סוג המכשיר, כי חלק מהמכשירים תומכים בכמה סוגים של מכשירים. המצב שמוחזר הוא שילוב של מצבי הקישוריות של כל התכונות במכשיר.
let lightConnectivity = dimmableLightDeviceType.metadata.sourceConnectivity .connectivityState
יכול להיות שתראו את המצב partiallyOnline אם יש לכם מכשירים מסוגים שונים ואין חיבור לאינטרנט. Matter יכול להיות שמאפיינים רגילים עדיין יהיו אונליין בגלל ניתוב מקומי, אבל מאפיינים מבוססי-ענן יהיו אופליין.
איך מוצאים את כתובת ה-IP של המכשיר
כדי למצוא את כתובת ה-IP של המכשיר, משתמשים במאפיין networkInterfaces של
GeneralDiagnosticsTrait.
הכתובות מוחזרות כאובייקטים מסוג Data, שאפשר לעצב אותם כמחרוזות IPv4 או IPv6 רגילות באמצעות מסגרת Network:
func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
let interfaces = trait.attributes.networkInterfaces ?? []
var ipAddresses: [String] = []
for interface in interfaces {
for data in interface.iPv4Addresses {
if let ipv4 = IPv4Address(data) {
ipAddresses.append(String(describing: ipv4))
}
}
for data in interface.iPv6Addresses {
if let ipv6 = IPv6Address(data) {
ipAddresses.append(String(describing: ipv6))
}
}
}
return ipAddresses
}
בדיקת ניתוב הרשת של מאפיין
הלוקאל של תכונה זמין גם בממשקי ה-API של Home. הסמל dataSourceLocality מציין אם התכונה מנותבת מרחוק (דרך הענן), באופן מקומי (דרך רכזת מקומית) או ישירות (ממכשיר למכשיר, ללא רכזת).
יכול להיות שערך המיקום הלא ידוע unspecified יופיע, למשל, בזמן שאפליקציה מופעלת ועדיין לא הגיעה למרכז או לשרת לצורך קישוריות המכשיר. אי אפשר להגיע למכשירים האלה, והם לא יגיבו לבקשות לאינטראקציה מפקודות או מאירועים. הלקוח קובע איך לטפל במכשירים כאלה.
let levelControlLocality = levelControlTrait.metadata.sourceConnectivity .dataSourceLocality
בדיקת ניתוב הרשת של מכשיר
בדומה לקישוריות, המקומיות נבדקת ברמת סוג המכשיר. המצב שמוחזר הוא שילוב של המיקום עבור כל התכונות במכשיר.
let lightLocality = dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality
מצב mixed יכול להופיע בתרחיש דומה לתרחיש של קישוריות partiallyOnline: חלק מהמאפיינים מבוססים על ענן וחלקם מקומיים.
שינוי השם של מכשיר
מבצעים קריאה לשיטה
setName(_:)
כדי לשנות את השם של מכשיר:
let updatedDevice = try await theDevice.setName("new device name")
כשמשנים את השם של מכשיר, מבנה הנתונים המקורי HomeDevice נשאר זהה והשינוי משתקף באובייקט HomeDevice המעודכן שמוחזר.
שמות ייחתכו אם הם יחרגו מהמגבלה של 60 נקודות קוד של Unicode (תווים), ולא יוצגו שגיאות. המפתחים אחראים לטיפול בשמות ארוכים. לדוגמה, הם יכולים להחליט אם הם רוצים ליידע את המשתמשים שהשמות יקוצרו.