دليل جهاز جرس الباب لنظام التشغيل iOS

يتم تنفيذ نوع الجهاز "جرس الباب" باستخدام سمتَين: PushAvStreamTransportTrait، التي تتعامل مع نقل بث الصوت والفيديو باستخدام بروتوكولات مستندة إلى الإرسال، و WebRtcLiveViewTrait، التي تتيح التحكّم في البث المباشر ووظيفة "التحدّث والاستماع".

يجب دائمًا التحقّق من توفّر السمات والأوامر لجهاز معيّن قبل استخدام أي ميزات أو محاولة تعديل السمات. لمزيد من المعلومات، اطّلِع على مقالة التحكّم في الأجهزة علىiOS.

نوع الجهاز في Home APIs السمات تطبيق Swift النموذجي حالة الاستخدام

جرس الباب

GoogleDoorbellDeviceType

home.matter.6006.types.0113

جهاز يتم تشغيله بواسطة زر خارج الباب ويصدر إشارة مسموعة و/أو مرئية، ويُستخدم لطلب انتباه شخص موجود في مكان ما على الجانب الآخر من الباب. قد تتضمّن أجراس الأبواب عمليات بث مباشر يسهل الوصول إليها أو ميزة التحدّث ثنائي الاتجاه أو أحداث الرصد.

السمات المطلوبة
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

جرس الباب

الحصول على معلومات أساسية عن جهاز

يتضمّن السمة BasicInformation معلومات، مثل اسم المورّد ومعرّف المورّد ومعرّف المنتج واسم المنتج (يتضمّن معلومات الطراز) وإصدار البرنامج للجهاز:

// [START get_device_information]
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!
// [END get_device_information]

الحصول على الرقم التسلسلي

للحصول على الرقم التسلسلي للجهاز، استخدِم الأمر GetSerialNumber الخاص بالسمة ExtendedBasicInformation. يعرض المثال حفظ الرقم التسلسلي في متغيّر اسمه serialNumber:

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

الردود السريعة

تتيح ميزة "الردود السريعة" للمستخدم إرسال رسالة محدّدة مسبقًا إلى جهاز جرس الباب.

تتوفّر هذه الميزة على أجهزة جرس الباب فقط. تتوفّر قائمة الرسائل المحدّدة مسبقًا لتطبيق الشريك، ويمكن أن يعرضها للمستخدم ليختار من بينها. لا يمكن للمستخدمين تعديل الرسائل المحدّدة مسبقًا.

يتم تنفيذ ميزة "الردود السريعة" من خلال السمة PresetMessage.

تشغيل رسالة مُعدّة مسبقًا

لتشغيل رسالة مُعدّة مسبقًا، استدعِ طريقة 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
}

بدء بث مباشر

لبدء بث مباشر، أرسِل سلسلة 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
  }
}

تمديد مدة بث مباشر

تتضمّن أحداث البث المباشر مدة محددة مسبقًا تنتهي بعدها صلاحيتها. لتمديد مدة البث النشط، أرسِل طلب تمديد باستخدام طريقة 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 وإيقافه

لبدء 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)")
  }
}

إدارة البث المباشر

يُعدّ تعديل جودة البث المباشر مفيدًا لتحسين استخدام معدل نقل البيانات استنادًا إلى سياق المشاهدة لدى العميل (على سبيل المثال، التبديل إلى دقة أقل عند عرض مربّع معاينة أصغر أو عرض على شكل مربّعات أو وضع "نافذة ضمن النافذة").

يؤدي تغيير الجودة بشكل ديناميكي باستخدام السمة 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 إلى طريقة PushAvStreamTransportTrait في السمة setTransportStatus(transportStatus:optionalArgsProvider:). لإيقاف إمكانية التسجيل، مرِّر القيمة 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
}

إعدادات البطارية

يمكن التحكّم في إعدادات البطارية المختلفة من خلال واجهات برمجة التطبيقات لمنزل Google.

ضبط إعدادات استخدام البطارية المفضَّلة

يسمح لك ضبط توازن الطاقة بتحديد المفاضلة بين عمر البطارية وأداء الجهاز. يمكنك إنشاء ملفات شخصية مختلفة للبطارية، مثل "عمر بطارية أطول" و"متوازن" و "أداء أفضل"، والتبديل بينها.

يتم تنفيذ هذه الميزة من خلال تعديل السمة 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)
  }
}

تفعيل ميزة "توفير شحن البطارية تلقائيًا"

لضبط هذه الميزة، عدِّل السمة currentLowPowerModeSensitivity في السمة EnergyPreference. تستخدم هذه السمة فهرسًا لاختيار مستوى حساسية، حيث يمثّل 0 عادةً Disabled، ويمثّل 1 Enabled أو Automatic.

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

الحصول على حالة شحن البطارية

للحصول على حالة الشحن الحالية للجهاز (جارٍ الشحن أو مشحون بالكامل أو لا يتم الشحن)، استخدِم السمة 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
}

إعدادات الصوت

يمكن التحكّم في إعدادات الصوت المختلفة من خلال واجهات برمجة التطبيقات Home APIs.

تفعيل الميكروفون أو إيقافه

لتفعيل ميكروفون الجهاز أو إيقافه، عدِّل السمة 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
  }
}

إعدادات منطقة النشاط

توفّر السمة ZoneManagement واجهة لإدارة المناطق المخصّصة التي تهمّك (مناطق النشاط) على أجهزة الكاميرا وأجراس الباب. تُستخدَم هذه المناطق لفلترة رصد الأحداث (مثل حركة الأشخاص أو المركبات) في مناطق محدّدة ضمن مجال رؤية الجهاز.

يتم ضبط مناطق النشاط من قِبل المستخدم داخل تطبيق شريك، ما يتيح له رسم مناطق فوق مساحات محدّدة في مجال رؤية الكاميرا. بعد ذلك، يتم تحويل هذه المناطق التي يحدّدها المستخدم إلى البُنى المستخدَمة في هذه السمة. لمزيد من المعلومات حول طريقة عمل "مناطق النشاط"، يُرجى الاطّلاع على مقالة إعداد "مناطق النشاط" واستخدامها.

يتم عادةً تحديد مناطق النشاط باستخدام إحداثيات ديكارتية ثنائية الأبعاد. توفّر السمة TwoDCartesianVertexStruct للرؤوس و TwoDCartesianZoneStruct لتعريف المنطقة (الاسم والرؤوس واللون والاستخدام).

التحقّق من مناطق النشاط

لعرض مناطق النشاط، ضَع علامة في المربّع بجانب السمة zones في السمة ZoneManagement.

let zoneManagementTrait: Google.ZoneManagementTrait

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

إضافة منطقة نشاط

لإنشاء منطقة جديدة، استخدِم الأمر createTwoDCartesianZone. يستخدِم هذا الأمر TwoDCartesianZoneStruct، الذي يحدّد اسم المنطقة ورؤوسها ولونها واستخدامها.

يوضّح المثال التالي كيفية إنشاء منطقة باسم "الشرفة الأمامية" بأربعة رؤوس، باللون الوردي الداكن (#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:

الوضع قيمة التعداد الوصف
الصوت 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
)

أوضاع التسجيل

توفّر السمة RecordingMode واجهة لإدارة سلوك تسجيل الفيديو والصور على أجهزة الكاميرا وأجراس الباب. ويتيح للمستخدمين الاختيار بين التسجيل المتواصل أو التسجيل فقط عند رصد حدث أو إيقاف التسجيل تمامًا (العرض المباشر فقط).

يحدّد RecordingModeEnum استراتيجيات التسجيل المتاحة:

الوضع قيمة التعداد الوصف
غير مفعَّلة Disabled تم إيقاف التسجيل نهائيًا. يتم استخدامه بشكل أساسي من خلال الأجهزة القديمة.
التسجيل المتواصل Cvr يتم تسجيل الفيديو على مدار الساعة طيلة أيام الأسبوع. يتطلب هذا الإجراء الاشتراك (على سبيل المثال، Google Home Premium.
التسجيل المستند إلى الأحداث (EBR) 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)
}

إعدادات أخرى

يمكن التحكّم في إعدادات أخرى متنوعة من خلال واجهات برمجة التطبيقات 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
  }
}

تغيير سطوع مؤشر LED للحالة

لتغيير مستوى سطوع مؤشر LED للحالة، استخدِم 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
  }
}

تغيير إطار عرض الكاميرا

إطار عرض الكاميرا هو نفسه ميزة &quot;التكبير والاقتصاص&quot; الموضّحة في مقالة المساعدة تكبير فيديو كاميرا 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 (راجِع مراقبة السحابة الإلكترونية لواجهات برمجة تطبيقات Home).

لتفعيل الإحصاءات لجهاز، اضبط السمة 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.

قراءة إعدادات النقل

يوضّح هذا القسم كيفية استرداد الإعدادات الحالية من كاميرا أو جرس باب. يتم استرداد السمة 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

إعدادات الجرس

يمكن التحكّم في إعدادات رنين جرس الباب المختلفة من خلال واجهات برمجة التطبيقات 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
  }
}

استخدام جرس خارجي

يمكن ضبط جرس الباب لاستخدام جرس خارجي، مثل جرس ميكانيكي مثبّت داخل المنزل. يجب ضبط هذا الإعداد أثناء عملية تثبيت جرس الباب لتجنُّب أي تلف محتمل في الجرس الخارجي.

لتحديد نوع الجرس الخارجي المثبَّت، استخدِم 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
  }
}

تغيير مدة رنين الجرس الخارجي

يمكن ضبط مدة رنين الجرس الخارجي بالثواني من خلال واجهات برمجة التطبيقات Home APIs. إذا كان الجرس الخارجي يتيح ضبط مدة الرنين، قد يريد المستخدم ضبط هذه المدة.

تعتمد القيمة المحدّدة هنا على مواصفات الجرس الخارجي نفسه، وعلى مدة الرنين الموصى بها.

لتغيير مدة الرنين الخارجي، عدِّل السمة externalChimeDurationSeconds في السمة ChimeTrait باستخدام الدالة المضمّنة setExternalChimeDurationSeconds:

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

تفعيل مظهر رنين

قد تتضمّن بعض أجراس الباب نغمات لا تتوفّر للمستخدمين إلا لفترة محدودة. على سبيل المثال، أصوات رنين خاصة بالعطلات. وتُعرف هذه الأصوات باسم "مواضيع الرنين".

لمعرفة مواضيع الرنين المتاحة لمستخدم معيّن، أنشئ فلترًا زمنيًا واستخدِمه لفلترة نتائج الأمر 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)
  }
}

إعدادات الإبلاغ بقدوم زوّار

يمكنك طلب إعدادات ميزة &quot;الإبلاغ بقدوم زوّار&quot; وإدارتها لأجراس الباب باستخدام السمة VisitorAnnouncement في واجهات برمجة التطبيقات Home APIs. تتحكّم هذه السمة في ما إذا كان يتم الإبلاغ عن قدوم زائر على مكبّرات الصوت أو شاشات العرض الذكية من Google عندما يقرع أحدهم جرس الباب.

يوضّح المثال التالي كيفية التحقّق مما إذا كانت ميزة &quot;الإبلاغ بقدوم زوّار&quot; مفعّلة وكيفية تعديل هذا الإعداد:

let visitorAnnouncementsEnabled: Bool = visitorAnnouncementTrait.attributes.visitorAnnouncementsEnabled

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