מדריך למכשיר פעמון הדלת ל-iOS

סוג המכשיר 'פעמון לדלת' מיושם באמצעות שתי תכונות: PushAvStreamTransportTrait, שמטפלת בהעברת סטרימינג של אודיו ווידאו באמצעות פרוטוקולים מבוססי-push, ו- WebRtcLiveViewTrait, שמספקת את היכולת לשלוט בשידורים חיים וב-TalkBack.

לפני שמשתמשים בתכונות או מנסים לעדכן מאפיינים, תמיד צריך לבדוק אם המכשיר תומך במאפיינים ובפקודות. מידע נוסף זמין במאמר שליטה במכשירים ב-iOS.

Home APIs Device Type תכונות אפליקציה לדוגמה של Swift תרחיש לדוגמה

פעמון דלת

GoogleDoorbellDeviceType

home.matter.6006.types.0113

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

מאפיינים נדרשים
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

Doorbell

קבלת מידע בסיסי על מכשיר

   Implemented in Sample App for iOS   

מאפיין BasicInformation כולל מידע כמו שם הספק, מזהה הספק, מזהה המוצר, שם המוצר (כולל פרטי הדגם) וגרסת התוכנה של המכשיר:

let vendorName = basicInfoTrait.attributes.vendorName!
let vendorID = basicInfoTrait.attributes.vendorID!
let productID = basicInfoTrait.attributes.productID!
let productName = basicInfoTrait.attributes.productName!
let softwareVersion = basicInfoTrait.attributes.softwareVersion!

קבלת מספר סידורי

   Implemented in Sample App for iOS   

כדי לקבל את המספר הסידורי של המכשיר, משתמשים בפקודה GetSerialNumber של מאפיין ExtendedBasicInformation. בדוגמה הזו, המספר הסידורי נשמר במשתנה בשם serialNumber:

// Assuming extendedBasicInformationTrait: Google.ExtendedBasicInformationTrait
let response = try await extendedBasicInformationTrait.getSerialNumber()
let serialNumber = response.serialNumber

תגובות מהירות אוטומטיות

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

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

התכונה 'תגובות מהירות' מיושמת באמצעות מאפיין PresetMessage.

איך משמיעים הודעה מוגדרת מראש

כדי להפעיל הודעה מוגדרת מראש, צריך להפעיל את method‏ playPresetMessage ולהעביר אליה אחד מערכי המחרוזת שמופיעים במאפיין availablePhraseTypes.


import GoogleHomeSDK
import GoogleHomeTypes

func playDoorbellPresetMessage(device: HomeDevice, phraseTypeString: String) async {
    // 1. Retrieve the GoogleDoorbellDeviceType helper on the device
    guard let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) else {
        print("This device is not a Google Doorbell or is currently uninitialized.")
        return
    }

    // 2. Extract the Google.PresetMessageTrait
    guard let presetMessageTrait = doorbellDeviceType.traits[Google.PresetMessageTrait.self] else {
        print("PresetMessageTrait is not supported on this device.")
        return
    }

    // 3. (Optional) Check available phrase types supported by the device
    if let availablePhrases = presetMessageTrait.attributes.availablePhraseTypes {
        let phraseTypeNames = availablePhrases.map { $0.phraseType }
        print("Supported quick response phrases: \(phraseTypeNames)")
    }

    // 4. Send the playPresetMessage command asynchronously
    do {
        try await presetMessageTrait.playPresetMessage(phraseType: phraseTypeString)
        print("Preset message successfully requested.")
    } catch {
        print("SDK error occurred playing preset message: \(error)")
    }
}

הגדרת שפת הדיבור

הגדרת שפת הדיבור

הגדרת השפה הפעילה המדוברת במכשיר ללוקאל ספציפי (לדוגמה, en_US) באמצעות השיטה setActiveLocale של המאפיין LocalizationConfiguration.

// Setting the active language
// Assuming localizationConfigurationTrait: Matter.LocalizationConfigurationTrait
let selectedLocale = "en_US"
try await localizationConfigurationTrait.update {
    $0.setActiveLocale(selectedLocale)
}

הזמן האחרון שבו המכשיר יצר קשר עם הענן

כדי למצוא את הפעם האחרונה שבה המכשיר יצר קשר עם הענן, משתמשים במאפיין lastContactTimestamp של מאפיין ExtendedGeneralDiagnostics:

if let lastContactTimeStamp = extendedGeneralDiagnosticsTrait.attributes.lastContactTimestamp {
  self.lastContactTime = Date(timeIntervalSince1970: Double(lastConnectedTimeStamp))
}

הגדרות של סוג התושבת של המצלמה

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

// 1. Get the Mount trait
guard let mountTrait = deviceType.traits[Google.MountTrait.self] else {
  print("Mount trait not supported or configured on this device.")
  return
}

// 2. Read the current mount state, detection type, and type name
let mountState         = mountTrait.attributes.mountState         // Type: Google.MountTrait.MountStateEnum?
let mountDetectionType = mountTrait.attributes.mountDetectionType // Type: Google.MountTrait.MountDetectionTypeEnum?
let mountTypeName      = mountTrait.attributes.mountTypeName      // Type: String?

// 3. Update the mount type override
try await mountTrait.update { mutableTrait in
  mutableTrait.setMountTypeOverride(.official)
}

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

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

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
}

התחלת שידור חי

   Implemented in Sample App for iOS   

כדי להתחיל שידור חי, שולחים את המחרוזת של Session Description Protocol ‏ (SDP) אל השיטה startLiveView(offerSdp:) של המאפיין WebRtcLiveViewTrait, שמחזירה שלושה ערכים:

  • נתוני ה-SDP של הסשן.
  • משך הביקור בשניות.
  • מזהה הסשן, שאפשר להשתמש בו כדי להאריך או לסיים את הסשן.
public func sendOffer(offerSdp: String) async throws
-> (answerSdp: String, mediaSessionId: String, liveViewDuration: TimeInterval)
{
  do {
    // Sending StartLiveView command
    let response = try await liveViewTrait.startLiveView(
      offerSdp: offerSdp
    )
    // Received StartLiveView response
    return (
      answerSdp: response.answerSdp,
      mediaSessionId: response.mediaSessionId,
      liveViewDuration: TimeInterval(response.liveSessionDurationSeconds)
    )
  } catch {
    // Failed to send StartLiveView command
    throw error
  }
}

הארכת שידור חי

   Implemented in Sample App for iOS   

לשידורים חיים יש משך זמן מוגדר מראש, ולאחר מכן הם מסתיימים. כדי להאריך את משך הזמן של שידור פעיל, צריך לשלוח בקשה להארכה באמצעות השיטה extendLiveView(mediaSessionId:optionalArgsProvider:):

public func extendLiveView(mediaSessionId: String) async throws {
  do {
    // Extending live view
    let extendedDuration = try await liveViewTrait.extendLiveView(mediaSessionId: mediaSessionId)
  } catch {
    // Failed to extend live view
    throw error
  }
}

התחלה והפסקה של TalkBack

   Implemented in Sample App for iOS   

כדי להפעיל את TalkBack, קוראים לשיטה startTalkback(mediaSessionId:optionalArgsProvider:) של המאפיין WebRtcLiveViewTrait. כדי להפסיק, משתמשים בפקודה stopTalkback(mediaSessionId:).

public func toggleTwoWayTalk(isOn: Bool, mediaSessionId: String) async throws {
  do {
    if isOn {
      try await liveViewTrait.startTalkback(mediaSessionId: mediaSessionId)
    } else {
      try await liveViewTrait.stopTalkback(mediaSessionId: mediaSessionId)
    }
  } catch {
    throw HomeError.commandFailed("Failed to toggle twoWayTalk: \(error)")
  }
}

ניהול שידור חי

   Implemented in Sample App for iOS   

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

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

בדוגמה הבאה אפשר לראות איך מאחזרים ומעדכנים את איכות השידור החי במכשיר:

  • אחזור אפשרויות איכות נתמכות: קבלת הרזולוציות הזמינות להזרמה שנתמכות על ידי המכשיר. הקוד שולח שאילתה למאפיין WebRtcLiveView כדי לחשוף את איכויות הסטרימינג הנתמכות כרשימה של ערכי QualityHint (כמו .sd,‏ .hd,‏ .fhd,‏ .qhd או .uhd) באמצעות המאפיין supportedQualityHints.

  • שינוי האיכות של השידור החי: בוחרים באפשרות QualityHint כדי לשנות את רזולוציית הסטרימינג של השידור החי הפעיל (לדוגמה, מעבר מהגדרה רגילה להגדרה גבוהה). הפונקציה updateQualityHint משתמשת בשיטה changeLiveViewQuality של המאפיין WebRtcLiveView כדי להחיל את ההגדרה QualityHint שנבחרה על סשן המדיה הפעיל.

public var supportedQualityHints: [Google.WebRtcLiveViewTrait.QualityHint] {
  return liveViewTrait?.attributes.supportedQualityHints ?? []
}

public func updateQualityHint(
  liveViewTrait: Google.WebRtcLiveViewTrait,
  hint: Google.WebRtcLiveViewTrait.QualityHint,
  mediaSessionId: String
) async {
  do {
    _ = try await liveViewTrait.changeLiveViewQuality(
      mediaSessionId: mediaSessionId,
      qualityHint: hint
    )
  } catch {
    // error
  }
}

הפעלה והשבתה של יכולת ההקלטה

כדי להפעיל את יכולת ההקלטה של המצלמה, מעבירים את הערך TransportStatusEnum.Active לשיטה setTransportStatus(transportStatus:optionalArgsProvider:) של מאפיין PushAvStreamTransportTrait. כדי להשבית את האפשרות להקלטה, מעבירים את הערך TransportStatusEnum.Inactive. בדוגמה הבאה, אנחנו עוטפים את הקריאות האלה בקריאה אחת שמשתמשת ב-Boolean כדי להפעיל או להשבית את יכולת ההקלטה:

public func toggleIsRecording(isOn: Bool) {
  self.uiState = .loading

  guard let pushAvStreamTransportTrait else {
    // PushAvStreamTransportTrait not found.
    return
  }
  Task {
    do {
      try await pushAvStreamTransportTrait.setTransportStatus(
        transportStatus: isOn ? .active : .inactive)
      if isOn {
        do {
          self.player = try self.createWebRtcPlayer()
        } catch {
          // Failed to initialize WebRtcPlayer
          self.uiState = .disconnected
          return
        }
        await self.player?.initialize()
        self.uiState = .live
      } else {
        self.player = nil
        self.uiState = .off
      }
    } catch {
      // Failed to toggle onOff
    }
  }
}

הפעלה או השבתה של יכולת ההקלטה של המצלמה זהות להפעלה או להשבתה של הווידאו מהמצלמה. כשהווידאו מהמצלמה מופעל, המצלמה מקליטה (למטרות של אירועים וקליפים קשורים).

כשהיכולת להקליט מושבתת (הווידאו מהמצלמה מושבת):

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

בודקים אם אפשרות ההקלטה מופעלת

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

public func isDeviceRecording() -> Bool {
  guard let pushAvStreamTransportTrait else {
    // PushAvStreamTransportTrait not found.
    return false
  }
  guard
    let hasActiveConnection =
      pushAvStreamTransportTrait
      .attributes
      .currentConnections?
      .contains(where: { $0.transportStatus == .active })
  else {
    return false
  }
  return hasActiveConnection
}

שחזור תמונות מצב מהמצלמה

אפשר להשתמש במאפיין CameraSnapshot כדי לאחזר תמונות סטטיות ממצלמה. קובצי ה-snapshot שימושיים בכמה תרחישים:

  • כאריח placeholder בממשק המשתמש בזמן הטעינה של שידור חי ב-WebRTC.
  • כתמונה סטטית לתצוגה מקדימה שמשתדרגת לשידור חי כשהמשתמש מקיים אינטראקציה.
  • כבד ציור ברקע להגדרת אזורי פעילות מותאמים אישית.

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

קבלת תמונת מצב של תצוגה מקדימה שנשמרה במטמון

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

כדי לקבל את תמונת המצב של התצוגה המקדימה, קוראים את מאפיין המאפיין preview_image_url:

guard let cameraSnapshotTrait = deviceType.traits[
  Google.CameraSnapshotTrait.self
] else {
  print("CameraSnapshot trait not supported on this device.")
  return
}

if let previewImageUrlString = cameraSnapshotTrait
  .attributes.preview_image_url,
   let url = URL(string: previewImageUrlString) {
  // Load the preview image from the URL
}

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

כדי לציין את עדכניות התמונה, הענן של Google Home מטמיע כותרת X-Home-Image-Captured-At בתמונה בפורמט JPEG/PNG שמוצגת, בפורמט UTC. אפשר לנתח את הכותרת הזו בצד הלקוח כדי להציג את גיל התמונה באפליקציה.

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

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

כדי לבקש תמונה עדכנית, משתמשים בפקודה getLiveSnapshot():

do {
  let response = try await cameraSnapshotTrait.getLiveSnapshot()
  let snapshotUrlString = response.snapshot_url

  if let url = URL(string: snapshotUrlString) {
    // Load the live snapshot image from the URL
  }
} catch {
  print("Failed to get live snapshot: \(error)")
}
.

אימות בקשות של תמונות מצב

כל כתובות ה-URL של התמונות מצביעות על מדיה מאובטחת ונדרש אסימון OAuth 2.0 בשביל היקף Home APIs v2. כדי להוריד את התמונות ולעבד אותן, צריך להוסיף את טוקן ה-OAuth כטוקן Bearer בכותרת Authorization של בקשת ה-HTTP.

בדוגמה הבאה אפשר לראות איך מגדירים בקשת רשת מאובטחת להורדת תמונת מצב:

import UIKit

func loadSnapshotImage(from url: URL, home: Home) async -> UIImage? {
  do {
    // 1. Retrieve the OAuth access token from the Home APIs SDK
    let (accessToken, _) = try await home.permissions.authorization()

    // 2. Configure the HTTP GET request with the Bearer token
    var request = URLRequest(url: url)
    request.setValue(
      "Bearer \(accessToken)",
      forHTTPHeaderField: "Authorization"
    )

    // 3. Fetch the image data
    let (data, _) = try await URLSession.shared.data(for: request)
    return UIImage(data: data)
  } catch {
    print("Error loading snapshot image: \(error)")
    return nil
  }
}

הגדרות הסוללה

אפשר לשלוט בהגדרות שונות של הסוללה באמצעות ממשקי ה-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"
    }
  ]
}
private func setBatteryUsage(to option: UInt8) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentEnergyBalance(option)
  }
}

הפעלה אוטומטית של מצב החיסכון בסוללה

   Implemented in Sample App for iOS   

כדי להגדיר את התכונה הזו, צריך לעדכן את המאפיין currentLowPowerModeSensitivity של מאפיין המאפיינים EnergyPreference. במאפיין הזה משתמשים באינדקס כדי לבחור רמת רגישות, כאשר 0 בדרך כלל מייצג Disabled ו-1 מייצג Enabled או Automatic.

private func setAutoBatterySaver(to value: Bool) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentLowPowerModeSensitivity(value ? 1 : 0)
  }
}

קבלת מצב הטעינה של הסוללה

   Implemented in Sample App for iOS   

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

self.chargingState = powerSourceTrait.attributes.batChargeState

var description: String
switch self.chargingState {
case .isCharging:
  description = "Charging"
case .isAtFullCharge:
  description = "Full"
case .isNotCharging:
  description = "Not Charging"
default:
  description = "Unknown"
}

קבלת רמת הטעינה

כדי לקבל את רמת הטעינה הנוכחית של הסוללה, משתמשים במאפיין batChargeLevel של המאפיין PowerSource. הרמה היא OK, Warning (נמוכה) או Critical.

self.batteryLevel = powerSourceTrait.attributes.batChargeLevel

var description: String
switch self.batteryLevel {
case .ok:
  description = "OK"
case .warning:
  description = "Warning"
case .critical:
  description = "Critical"
default:
  description = "Unknown"
}

קבלת מקור הכוח

כדי לקבוע את מקור החשמל שבו המכשיר משתמש, צריך להשתמש במאפיינים BatPresent ו-wiredPresent של מאפיין PowerSource.

if powerSourceTrait.attributes.wiredPresent ?? false {
  self.powerSourceType = .wired
} else if powerSourceTrait.attributes.batPresent ?? false {
  self.powerSourceType = .battery
} else {
  self.powerSourceType = nil
}

בודקים אם צריך להחליף את הסוללה

מאפיין batReplaceability מציין אם הסוללה לא ניתנת להחלפה, ניתנת להחלפה על ידי המשתמש או ניתנת להחלפה במפעל.

אם אפשר להחליף את הסוללה, המאפיין batReplacementNeeded של התכונה PowerSource מציין אם צריך להחליף את הסוללה.

// Get the battery replacement status
var batteryStatus = powerSourceTrait.attributes.batReplacementNeeded

if batteryStatus {
  print("Replace the battery.")
}

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

הגדרות אודיו

אפשר לשלוט בהגדרות שונות של אודיו באמצעות ממשקי ה-API של Home.

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

כדי להפעיל או להשבית את המיקרופון במכשיר, מעדכנים את מאפיין microphoneMuted של מאפיין התכונה CameraAvStreamManagementTrait באמצעות הפונקציה המובנית setMicrophoneMuted:

// Turn the device's microphone on or off
func setMicrophone(on: Bool) async {
  do {
    _ = try await self.cameraAvStreamManagementTrait?.update {
      $0.setMicrophoneMuted(!on)
    }
  } catch {
    // Error
  }
}

הפעלה או השבתה של הקלטת אודיו

כדי להפעיל או להשבית את הקלטת האודיו במכשיר, מעדכנים את המאפיין recordingMicrophoneMuted של מאפיין CameraAvStreamManagementTrait באמצעות הפונקציה המובנית setRecordingMicrophoneMuted:

// Turn audio recording on or off for the device
func setAudioRecording(on: Bool) async {
  do {
    _ = try await self.cameraAvStreamManagementTrait?.update {
      $0.setRecordingMicrophoneMuted(!on)
    }
  } catch {
    // Error
  }
}

שינוי עוצמת הקול של הרמקול

כדי לשנות את עוצמת הקול של הרמקול במכשיר, צריך לעדכן את מאפיין speakerVolumeLevel של תכונת CameraAvStreamManagementTrait באמצעות הפונקציה המובנית setSpeakerVolumeLevel:

// Adjust the camera speaker volume
func setSpeakerVolume(to value: UInt8) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setSpeakerVolumeLevel(value)
    }
  } catch {
    // Error
  }
}

הגדרות של אזורי פעילות

   Implemented in Sample App for iOS   

מאפיין ZoneManagement מספק ממשק לניהול אזורים מותאמים אישית שמעניינים אתכם (אזורי פעילות) במצלמות ובפעמוני דלת. האזורים האלה משמשים לסינון של זיהוי אירועים (כמו תנועה של אנשים או כלי רכב) באזורים ספציפיים בשדה הראייה של המכשיר.

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

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

בדיקת אזורי הפעילות

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

let zoneManagementTrait: Google.ZoneManagementTrait

self.zones = zoneManagementTrait.attributes.zones ?? []

הוספת אזור פעילות

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

בדוגמה הבאה מוצג איך ליצור אזור בשם Front Porch עם ארבע נקודות, בצבע סלמון (#F439A0), שמשמש לזיהוי תנועה.

import GoogleHomeSDK
import GoogleHomeTypes

func createFrontPorchZone(trait: Google.ZoneManagementTrait) async {
  // 1. Define the vertices for the zone (2D Cartesian coordinates)
  // Values are UInt16, typically scaled to the device's twoDCartesianMax.
  let vertices = [
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 260, y = 422),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1049, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 950),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1630, y = 1349),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 880, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 0, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 638, y = 1090)
  ]

  // 2. Define the zone structure using the given SDK struct
  let newZone = Google.ZoneManagementTrait.TwoDCartesianZoneStruct(
    name: "Front Porch",
    use: [.motion], // ZoneUseEnum.motion
    vertices: vertices,
    // Color is a hex string (for example, Salmon/Pink)
    color: "#F439A0"
  )

  do {
    // 3. Execute the raw command to add the zone to the device
    // This returns the created zone's ID (UInt16).
    var newZoneID = try await trait.createTwoDCartesianZone(zone: newZone)
  } catch {
    // Error
  }
}

עדכון אזור פעילות

כדי לעדכן אזור קיים, משתמשים בפקודה updateTwoDCartesianZone. הפקודה הזו דורשת את zoneId ואת TwoDCartesianZoneStruct המעודכן.

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16
let zone: Google.ZoneManagementTrait.TwoDCartesianZoneStruct

do {
  _ = try await zoneManagementTrait.updateTwoDCartesianZone(
        zoneID: zoneID, zone: zone)
} catch {
  // Error
}

מחיקת אזור פעילות

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

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16

do {
  _ = try await zoneManagementTrait.removeZone(zoneID: zoneID)
} catch {
  // Error
}

טריגרים של אירועים של זיהוי צליל

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

אלה סוגי הטריגרים שזמינים לזיהוי צלילים באמצעות EventTriggerTypeEnum:

מצב ערך enum תיאור
צליל Sound זיהוי צלילים כללי.
מישהו מדבר PersonTalking זיהוי דיבור.
נביחת כלב DogBark מזהה קולות של כלבים.
זכוכית נשברת GlassBreak זיהוי צליל של זכוכית נשברת.
גלאי עשן SmokeAlarm המכשיר מזהה התראות עשן, שלרוב מזוהות לפי דפוס קולי T3 (שלושה צפצופים קצרים ואז הפסקה).
גלאי פחמן חד-חמצני CoAlarm מזהה אזעקות של פחמן חד-חמצני (CO), שבדרך כלל מזוהות לפי דפוס הצליל T4 (ארבע צפצופים קצרים ואז הפסקה).

בדיקת הסטטוס של זיהוי הצלילים

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

בפיתוח ל-iOS, בדרך כלל ניגשים למאפיין AvStreamAnalysis מהמכשיר כדי לקרוא את המאפיינים האלה.

// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait

let possibleEventTriggers = avStreamAnalysisTrait.attributes.supportedEventTriggers ?? []
let enabledEventTriggers = avStreamAnalysisTrait.attributes.enabledEventTriggers ?? []

let eventTriggers [EventTrigger] = []
for trigger in possibleEventTriggers {
  self.eventTriggers.append(
    EventTrigger(
      id: trigger,
      enabled: enabledEventTriggers.contains(trigger)
    )
  )
}

עדכון של קבוצת הטריגרים המופעלים

כדי לעדכן את קבוצת הטריגרים המופעלים, משתמשים בפקודה SetOrUpdateEventDetectionTriggers, שמקבלת רשימה של מבני EventTriggerEnablement.

// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait
let eventTriggers: [EventTrigger]

let enabledEventTriggers = eventTriggers.map {
  Google.AvStreamAnalysisTrait.EventTriggerEnablement(
    eventTriggerType: $0.id,
    enablementStatus: $0.enabled ? .enabled : .disabled
  )
}

try await avStreamAnalysisTrait.setOrUpdateEventDetectionTriggers(
  eventTriggerEnablements: enabledEventTriggers
)

מצבי הקלטה

   Implemented in Sample App for iOS   

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

ההגדרה RecordingModeEnum מגדירה את אסטרטגיות ההקלטה הזמינות:

מצב ערך enum תיאור
מושבת Disabled ההקלטה מושבתת לחלוטין. משמש בעיקר מכשירים מדור קודם.
CVR (הקלטת וידאו רציפה) Cvr הסרטון מוקלט מסביב לשעון. נדרש מינוי (לדוגמה, Google Home Premium.
EBR (Event Based Recording) Ebr ההקלטה מופעלת על ידי אירועים (אדם, תנועה). אורך הסרטון תלוי במשך האירוע ובמינוי.
ETR (הקלטה שמופעלת על ידי אירוע) Etr הקלטה של תצוגה מקדימה קצרה (לדוגמה, 10 שניות) מופעלת על ידי אירועים.
תצוגה חיה LiveView ההקלטה מושבתת, אבל המשתמשים עדיין יכולים לגשת לשידור החי.
תמונות סטילס Images במקום סרטונים, המצלמה מצלמת תמונות סטילס כשיש אירועים.

בדיקת מצבי ההקלטה

כדי להציג את הגדרות ההקלטה הנוכחיות, בודקים את המאפיינים של מאפיין RecordingMode:

// Example struct to store recording modes.
public struct RecordingMode: Hashable {
  public let id: UInt8
  public let mode: Google.RecordingModeTrait.RecordingModeEnum
}

let recordingModeTrait: Google.RecordingModeTrait

if let availableRecordingModes = recordingModeTrait.attributes.availableRecordingModes,
   let supportedRecordingModes = recordingModeTrait.attributes.supportedRecordingModes,
   let selectedRecordingMode = recordingModeTrait.attributes.selectedRecordingMode {

  var recordingModes: [RecordingMode] = []

  for recordingModeId in availableRecordingModes {
    guard Int(recordingModeId) < supportedRecordingModes.count,
          Int(recordingModeId) >= 0 else {
      // Out of bounds error
    }

    recordingModes.append(
      RecordingMode(
        id: recordingModeId,
        mode: supportedRecordingModes[Int(recordingModeId)].recordingMode,
      )
    )
  }
}

שינוי מצב ההקלטה

לפני העדכון, מוודאים שהאינדקס שנבחר מהמאפיין supportedRecordingModes מופיע במאפיין availableRecordingModes.

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

let recordingModeTrait: Google.RecordingModeTrait
let recordingModeID: UInt8

_ = try await recordingModeTrait.update {
  $0.setSelectedRecordingMode(recordingModeID)
}

הגדרות אחרות

אפשר לשלוט בהגדרות שונות אחרות באמצעות ממשקי ה-API של Home.

הפעלה או השבתה של ראיית לילה

כדי להפעיל או להשבית את ראיית הלילה במצלמה, משתמשים ב-TriStateAutoEnum כדי לעדכן את מאפיין nightVision של תכונת CameraAvStreamManagementTrait באמצעות הפונקציה המובנית setNightVision:

// Turn night vision on or off
func setNightVision(
  to value: Google.CameraAvStreamManagementTrait.TriStateAutoEnum
) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setNightVision(value)
    }
  } catch {
    // Error
  }
}

שינוי הבהירות של נורית הסטטוס

כדי לשנות את הבהירות של נורית הסטטוס, משתמשים ב-ThreeLevelAutoEnum כדי לעדכן את המאפיין statusLightBrightness של מאפיין התכונה CameraAvStreamManagementTrait באמצעות הפונקציה המובנית setStatusLightBrightness:

// Set the LED brightness
func setStatusLightBrightness(
  to value: Google.CameraAvStreamManagementTrait.ThreeLevelAutoEnum
) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setStatusLightBrightness(value)
    }
  } catch {
    // Error
  }
}

שינוי אזור התצוגה של המצלמה

אזור התצוגה של המצלמה זהה לתכונה 'התקרבות וחיתוך' שמתוארת במאמר התמיכה בנושא התקרבות והגדלה של סרטונים ממצלמת Nest.

הגדרת אזור התצוגה מתבצעת באמצעות תג ViewportStruct שמכיל ארבעה ערכים, שמשמשים כקואורדינטות של אזור התצוגה. הקואורדינטות מוגדרות כך:

(x1,y1) -- (x2,y1)
   |          |
(x1,y2) -- (x2,y2)

הערכים של ViewportStruct נקבעים לפי ממשק המשתמש של האפליקציה והיישום של המצלמה. ברמה הבסיסית ביותר, כדי להגדיר את אזור התצוגה של סרטון המצלמה, צריך לעדכן את מאפיין viewport של מאפיין CameraAvStreamManagementTrait באמצעות ViewportStruct, באמצעות הפונקציה המובנית setViewport.

func setCrop(x1: UInt16, y1: UInt16, x2: UInt16, y2: UInt16) {

  let viewport = Google.CameraAvStreamManagementTrait.ViewportStruct(
    x1: x1,
    y1: y1,
    x2: x2,
    y2: y2
  )

  Task {
    do {
      try await cameraAvStreamManagementTrait.update {
        $0.setViewport(viewport)
      }
    } catch {
      // Error
    }
  }

}

יצירת TransportOptionsStruct

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

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

func getTransportOptions(
  transportOptions: Google.PushAvStreamTransportTrait.TransportOptionsStruct,
  wakeUpSensitivity: UInt8?,
  maxEventLength: UInt32?
) async throws
  -> Google.PushAvStreamTransportTrait.TransportOptionsStruct
{

  var newMotionTimeControl:
    Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct? = nil
  if let maxEventLength {
    guard let motionTimeControl = transportOptions.triggerOptions.motionTimeControl else {
      throw HomeError.failedPrecondition(
        // Error - cannot update max event length without motion time control
    }
    newMotionTimeControl =
      Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
        initialDuration: motionTimeControl.initialDuration,
        augmentationDuration: motionTimeControl.augmentationDuration,
        maxDuration: maxEventLength,
        blindDuration: motionTimeControl.blindDuration
      )
  }

  return Google.PushAvStreamTransportTrait.TransportOptionsStruct(
    streamUsage: .recording,
    videoStreamID: nil,
    audioStreamID: nil,
    tlsEndpointID: transportOptions.tlsEndpointID,
    url: transportOptions.url,
    triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
      triggerType: .motion,
      motionZones: nil,
      motionSensitivity: wakeUpSensitivity,
      motionTimeControl: newMotionTimeControl,
      maxPreRollLen: nil
    ),
    ingestMethod: .cmafIngest,
    containerOptions: Google.PushAvStreamTransportTrait.ContainerOptionsStruct(
      containerType: .cmaf,
      cmafContainerOptions: nil
    ),
    expiryTime: nil
  )
}

private func getRecordingConnection() async throws
  -> Google.PushAvStreamTransportTrait.TransportConfigurationStruct?
{
  guard let pushAvStreamTransportTrait else {
    // Error - PushAvStreamTransport trait not available
    return nil
  }

  let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations

  for connection in connections {
    guard let transportOptions = connection.transportOptions,
      transportOptions.streamUsage == .recording
    else {
      continue
    }

    return connection
  }

  return nil
}

הפעלה או השבתה של ניתוח נתונים

כל מכשיר יכול להצטרף בנפרד לשליחת נתוני ניתוח מפורטים אל ענן Google Home (ראו Cloud Monitoring for Home APIs).

כדי להפעיל את ניתוח הנתונים במכשיר, צריך להגדיר את המאפיין analyticsEnabled) של ExtendedGeneralDiagnosticsTrait לערך true. כשמגדירים את analyticsEnabled, נכס אחר, logUploadEnabled, מוגדר אוטומטית ל-true, מה שמאפשר להעלות את קובצי יומן הניתוח לענן של Google Home.

// Enable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(true)
}

// Disable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(false)
}

הגדרות של שינוע והקלטה

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

קריאת הגדרות התעבורה

בקטע הזה נסביר איך לאחזר את ההגדרה הנוכחית ממצלמה או ממכשיר Nest Doorbell. הוא מאחזר את מאפיין PushAvStreamTransport, מוצא את החיבור הספציפי ששימש להקלטה, ואז מחלץ את הערכים הנוכחיים של איכות רוחב הפס, הרגישות ליציאה ממצב שינה ואורך האירוע המקסימלי.

// Assuming access to
// var pushAvStreamTransportTrait: Google.PushAvStreamTransportTrait
let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations

// Locate the connection designated for recording
let recordingConnection = connections.first { connection in
    guard let transportOptions = connection.transportOptions else { return false }
    return transportOptions.streamUsage == .recording
}

let options = recordingConnection?.transportOptions

// 1. Bandwidth Quality (Video Stream ID)
let videoStreamId = options?.videoStreamID

// 2. Wake-up Sensitivity (Motion Sensitivity)
let wakeUpSensitivity = options?.triggerOptions.motionSensitivity

// 3. Max Event Length (Motion Trigger Time Control)
let maxEventLength = options?.triggerOptions.motionTimeControl?.maxDuration

עדכון הגדרות התעבורה

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

כדי לשנות את ההגדרות האלה, משתמשים בפקודה modifyPushTransport עם TransportOptionsStruct.

// Example: Updating to Max Quality and 30s duration
let currentOptions = recordingConnection!.transportOptions!
let newOptions = Google.PushAvStreamTransportTrait.TransportOptionsStruct(
    streamUsage: .recording,
    videoStreamID: 2, // Max Quality
    tlsEndpointID: currentOptions.tlsEndpointID,
    url: currentOptions.url,
    triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
        triggerType: .motion,
        motionSensitivity: 5, // Medium
        motionTimeControl: Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
            initialDuration: currentOptions.triggerOptions.motionTimeControl?.initialDuration ?? 10,
            augmentationDuration: currentOptions.triggerOptions.motionTimeControl?.augmentationDuration ?? 5,
            maxDuration: 30,
            blindDuration: currentOptions.triggerOptions.motionTimeControl?.blindDuration ?? 0
        )
    ),
    ingestMethod: currentOptions.ingestMethod,
    containerOptions: currentOptions.containerOptions
)

try await pushAvStreamTransportTrait.modifyPushTransport(
    connectionID: recordingConnection!.connectionID,
    transportOptions: newOptions
)

קביעת איכות רוחב הפס

המאפיין videoStreamId של TransportOptionsStruct מתאים להגדרה ספציפית של סטרימינג של סרטון.

כדי לקבל את זרמי הווידאו הנתמכים, צריך לעיין במאפיין allocatedVideoStreams, שהוא רשימה של VideoStreamStructs. מהמאפיין CameraAvStreamManagement של המכשיר.

שינוי הרגישות של יציאה ממצב שינה

המאפיין motionSensitivity של TransportTriggerOptionsStruct תואם לערכים הבאים:

תווית ערך (UInt8)
נמוכה 1
בינונית 5
גבוהה 10

שינוי משך האירוע המקסימלי

המאפיין maxDuration של TransportMotionTriggerTimeControlStruct תואם למשכי הזמן הבאים של UInt32 (בשניות):

  • 10, ‏ 15, ‏ 30, ‏ 60, ‏ 120, ‏ 180

הגדרות של Chime

אפשר לשלוט בהגדרות שונות של צלצול בדלת באמצעות ממשקי ה-API של Home.

שינוי הצליל של מנגנון הצלצול

כדי לשנות את צליל הפעמון בדלת, קודם צריך לקבל את רשימת הצלילים של הפעמון שמותקנים במכשיר באמצעות מאפיין installedChimeSounds של תכונת ChimeTrait:

doorbellChimeTrait.attributes.installedChimeSounds?.compactMap { chimeSound in
  return chimeSound.chimeID, chimeSound.name
}

לאחר מכן, מעדכנים את מאפיין selectedChime של מאפיין ChimeTrait באמצעות הפונקציה המובנית setSelectedChime:

func setDoorbellChime(chimeID: UInt8) async {
  do {
    _ = try await doorbellChimeTrait.update {
      $0.setSelectedChime(chimeID)
    }
  } catch {
    // Error
  }
}

שימוש במנגנון צלצול חיצוני

   Implemented in Sample App for iOS   

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

כדי לציין איזה סוג של מנגנון צלצול חיצוני מותקן, צריך להשתמש ב-ExternalChimeType כדי לעדכן את המאפיין externalChime של מאפיין התכונה ChimeTrait באמצעות הפונקציה המובנית setExternalChime:

// Indicate the external chime is mechanical
func setExternalChime(to value: Google.ChimeTrait.ExternalChimeType) async {
  do {
    _ = try await doorbellChimeTrait.update {
      $0.setExternalChime(value)
    }
  } catch {
    // Error
  }
}

שינוי משך הצלצול החיצוני

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

הערך שמוגדר כאן תלוי במפרט של מנגנון הצלצול החיצוני עצמו, ובמשך הצלצול המומלץ שלו.

כדי לשנות את משך הצלצול החיצוני, מעדכנים את המאפיין externalChimeDurationSeconds של מאפיין ChimeTrait באמצעות הפונקציה המובנית setExternalChimeDurationSeconds:

// Change the external chime duration
func setExternalChimeDuration(to value: UInt16) async {
  do {
    _ = try await doorbellChimeTrait.update {
      $0.setExternalChimeDuration(value)
    }
  } catch {
    // Error
  }
}

הפעלת עיצוב של צליל התראה

   Implemented in Sample App for iOS   

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

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

בדוגמה הבאה אפשר לראות איך מסננים את הרשימה. עיצוב נחשב פעיל אם השעה הנוכחית חלה בין שעת ההתחלה לשעת הסיום שלו (הערכים startTimeSeconds ו-endTimeSeconds, בהתאמה). אם לא מוגדרת שעת התחלה, המבצע נחשב פעיל מתחילת הזמן. אם לא מגדירים זמן סיום, ההגדרה ממשיכה להיות פעילה ללא הגבלת זמן. אם שני הערכים חסרים, העיצוב תמיד פעיל.

let chimeThemes = try await chimeThemeTrait.getAvailableThemes().themes

if !chimeThemes.isEmpty {
  var chimeThemeSettings = []
  for chimeTheme in chimeThemes {
    let currentDateTime = UInt64(Date().timeIntervalSince1970)

    // Only show chime themes that are active.
    if chimeTheme.startTimeSeconds ?? 0 &lt;= currentDateTime
      &amp;&amp; chimeTheme.endTimeSeconds ?? UInt64.max &gt;= currentDateTime
    {
      self.chimeThemeSettings.append(chimeTheme.name)
    }
  }
}

אחרי שמקבלים את שם העיצוב הרצוי, כמו Christmas, אפשר לבחור אותו באמצעות הפונקציה setSelectedTimeboxedThemeName() במאפיין ChimeThemes ChimeThemes.

private func setChimeTheme(to value: String) async throws {
  _ = try await chimeThemeTrait.update {
    $0.setSelectedTimeboxedThemeName(value)
  }
}

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

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

בדוגמה הבאה אפשר לראות איך בודקים אם ההודעות על מבקרים מופעלות ואיך מעדכנים את ההגדרה הזו:

let visitorAnnouncementsEnabled: Bool = visitorAnnouncementTrait.attributes.visitorAnnouncementsEnabled

let value: Bool
_ = try await self.visitorAnnouncementTrait?.update {
  $0.setVisitorAnnouncementsEnabled(value)
}