راهنمای دستگاه زنگ در برای iOS

نوع دستگاه Doorbell با استفاده از دو ویژگی پیاده‌سازی می‌شود: PushAvStreamTransportTrait که انتقال جریان صوتی و تصویری را با استفاده از پروتکل‌های مبتنی بر فشار مدیریت می‌کند، و WebRtcLiveViewTrait که امکان کنترل پخش زنده و talkback را فراهم می‌کند.

قبل از استفاده از هرگونه ویژگی یا تلاش برای به‌روزرسانی ویژگی‌ها، همیشه پشتیبانی از ویژگی‌ها و دستورات را برای دستگاه بررسی کنید. به بخش کنترل دستگاه‌ها مراجعه کنید.iOS برای اطلاعات بیشتر.

نوع دستگاه APIهای خانگی صفات نمونه برنامه سویفت مورد استفاده

زنگ در

Google Doorbell DeviceType

home.matter.6006.types.0113

دستگاهی که توسط دکمه‌ای در بیرون در فعال می‌شود و سیگنال صوتی و/یا بصری ایجاد می‌کند و برای جلب توجه شخصی که در آن سوی در است، استفاده می‌شود. زنگ درها ممکن است دارای پخش زنده قابل دسترسی، مکالمه دو طرفه یا رویدادهای تشخیص باشند.

ویژگی‌های مورد نیاز
google PushAvStreamTransportTrait
گوگل 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!
let serialNumber = basicInfoTrait.attributes.serialNumber!
// [END get_device_information]

آخرین زمان تماس ابری دستگاه را دریافت کنید

برای یافتن آخرین زمانی که دستگاه با فضای ابری تماس داشته است، از ویژگی lastContactTimestamp از ویژگی ExtendedGeneralDiagnostics استفاده کنید:

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

بررسی اتصال دستگاه

اتصال برای یک دستگاه در واقع در سطح نوع دستگاه بررسی می‌شود زیرا برخی از دستگاه‌ها از چندین نوع دستگاه پشتیبانی می‌کنند. حالت برگردانده شده ترکیبی از حالت‌های اتصال برای همه ویژگی‌های آن دستگاه است.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

در صورت عدم اتصال به اینترنت، ممکن است در مورد انواع دستگاه‌های ترکیبی، حالت partiallyOnline مشاهده شود. ویژگی‌های استاندارد Matter ممکن است به دلیل مسیریابی محلی هنوز آنلاین باشند، اما ویژگی‌های مبتنی بر ابر آفلاین خواهند بود.

شروع پخش زنده

برای شروع پخش زنده، رشته‌ی پروتکل شرح جلسه (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
  }
}

پخش زنده را تمدید کنید

پخش زنده (Livestream) دارای مدت زمان از پیش تعیین شده‌ای است که پس از آن منقضی می‌شود. برای افزایش مدت زمان یک پخش زنده فعال، با استفاده از متد 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، متد 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)")
  }
}

فعال و غیرفعال کردن قابلیت ضبط

برای فعال کردن قابلیت ضبط دوربین، 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
}

تنظیمات باتری

تنظیمات مختلف باتری را می‌توان از طریق 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)
  }
}

فعال کردن ذخیره خودکار باتری

برای پیکربندی این ویژگی، ویژگی 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
}

تنظیمات صوتی

تنظیمات مختلف صوتی را می‌توان از طریق 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
  }
}

تنظیمات منطقه فعالیت

ویژگی 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 (سه بوق کوتاه و به دنبال آن یک مکث) شناخته می‌شوند.
هشدار CO 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 (ضبط مداوم ویدیو) Cvr ویدیو به صورت ۲۴ ساعته و ۷ روز هفته ضبط می‌شود. نیاز به اشتراک دارد (برای مثال، Google Google Home Premium .)
EBR (ضبط مبتنی بر رویداد) Ebr ضبط توسط رویدادها (شخص، حرکت) آغاز می‌شود. طول ویدیو به مدت زمان رویداد و اشتراک بستگی دارد.
ETR (ضبط بر اساس رویداد) Etr ضبط پیش‌نمایش کوتاه (مثلاً ۱۰ ثانیه) که توسط رویدادها فعال می‌شود.
نمایش زنده 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
  }
}

تغییر روشنایی 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
  }
}

تغییر زاویه دید دوربین

نمای دوربین همان ویژگی بزرگنمایی و برش است که در مقاله پشتیبانی از ویدیوی دوربین Nest با بزرگنمایی و بهبود، توضیح داده شده است.

نمای دید (viewport) در یک 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، این ساختار باید قبل از به‌روزرسانی هرگونه ویژگی ایجاد شود.

از این تابع کمکی برای تولید ساختار (struct) مورد استفاده با تغییرات تنظیمات زیر استفاده کنید:

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
}

حساسیت بیدار شدن دستگاه را تنظیم کنید

حساسیت بیدار شدن دستگاه برای صرفه‌جویی در مصرف باتری استفاده می‌شود، به این صورت که محدوده‌ای که دستگاه می‌تواند فعالیت را حس کند کاهش می‌یابد و زمان بیدار شدن پس از تشخیص آن فعالیت افزایش می‌یابد.

در APIهای Home، این مورد را می‌توان با استفاده از ویژگی motionSensitivity از triggerOptions در transportOptions دستگاه تنظیم کرد. این گزینه‌ها در ویژگی PushAvStreamTransportTrait برای هر دستگاه تعریف شده‌اند.

حساسیت بیدارباش فقط می‌تواند روی مقادیر زیر تنظیم شود:

  • ۱ = کم
  • ۵ = متوسط
  • ۱۰ = زیاد

فرآیند به‌روزرسانی به این صورت است که پیکربندی انتقال برای جریان‌های ضبط فعال با استفاده از دستور findTransport پیدا می‌شود، سپس پیکربندی با مقدار حساسیت جدید با استفاده از دستور modifyPushTransport اصلاح می‌شود.

دستور modifyPushTransport نیاز به ارسال کامل TransportOptionsStruct دارد، بنابراین ابتدا باید مقادیر موجود را از پیکربندی فعلی کپی کنید. برای مشاهده یک تابع کمکی برای انجام این کار، به بخش Generate a TransportOptionsStruct مراجعه کنید.

func setWakeUpSensitivity(to value: UInt8) async {
  do {
    let connection = try await getRecordingConnection()
    guard let connection,
      let transportOptions = connection.transportOptions
    else {
      // Error - Transport options not available
      return
    }

    guard transportOptions.triggerOptions.motionSensitivity != nil else {
      // Error - Motion sensitivity not available to be updated for this device
      return
    }

    try await pushAvStreamTransportTrait.modifyPushTransport(
      connectionID: connection.connectionID,
      transportOptions: self.getTransportOptions(
        transportOptions: transportOptions,
        wakeUpSensitivity: value,
        maxEventLength: nil
      )
    )

  } catch {
    // Error
  }
}

حداکثر طول رویداد را تنظیم کنید

حداکثر طول رویداد، مدت زمانی است که دوربین کلیپی از یک رویداد ضبط می‌کند. از طریق APIهای Home، این مدت زمان را می‌توان برای هر دستگاه، با همان طول زمانی که از طریق Google Home app (GHA) تنظیم می‌شود، در فواصل ثانیه تنظیم کرد:

  • ۱۰ ثانیه
  • ۱۵ ثانیه
  • ۳۰ ثانیه
  • ۶۰ ثانیه (۱ دقیقه)
  • ۱۲۰ ثانیه (۲ دقیقه)
  • ۱۸۰ ثانیه (۳ دقیقه)

در APIهای Home، این مورد را می‌توان با استفاده از ویژگی motionTimeControl از triggerOptions در transportOptions دستگاه تنظیم کرد. این گزینه‌ها در ویژگی PushAvStreamTransportTrait برای هر دستگاه تعریف شده‌اند.

فرآیند به‌روزرسانی به این صورت است که پیکربندی انتقال برای جریان‌های ضبط فعال با استفاده از دستور findTransport پیدا می‌شود، سپس پیکربندی با مقدار طول رویداد جدید با استفاده از دستور modifyPushTransport اصلاح می‌شود.

دستور modifyPushTransport نیاز به ارسال کامل TransportOptionsStruct دارد، بنابراین ابتدا باید مقادیر موجود را از پیکربندی فعلی کپی کنید. برای مشاهده یک تابع کمکی برای انجام این کار، به بخش Generate a TransportOptionsStruct مراجعه کنید.

func setMaxEventLength(to value: UInt32) async {
  do {
    let connection = try await getRecordingConnection()
    guard let connection,
      let transportOptions = connection.transportOptions
    else {
      // Error - Transport options not available
      return
    }

    guard transportOptions.triggerOptions.motionTimeControl != nil else {
      // Error - Motion time control not available to be updated for this device
      return
    }

    try await pushAvStreamTransportTrait.modifyPushTransport(
      connectionID: connection.connectionID,
      transportOptions: self.getTransportOptions(
        transportOptions: transportOptions,
        wakeUpSensitivity: nil,
        maxEventLength: value
      )
    )

  } catch {
    // Error
  }
}

فعال یا غیرفعال کردن تجزیه و تحلیل

هر دستگاه می‌تواند به صورت جداگانه ارسال داده‌های تحلیلی دقیق به فضای ابری گوگل هوم را انتخاب کند (به بخش نظارت ابری برای APIهای خانگی مراجعه کنید).

برای فعال کردن تجزیه و تحلیل برای یک دستگاه، ویژگی 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)
}

تنظیمات زنگ

تنظیمات مختلف زنگ در را می‌توان از طریق APIهای خانه کنترل کرد.

صدای زنگ را تغییر دهید

برای تغییر صدای زنگ در، ابتدا لیست صداهای زنگی که روی دستگاه نصب شده‌اند را با استفاده از ویژگی installedChimeSounds از ویژگی ChimeTrait دریافت کنید:

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

سپس، با استفاده از تابع داخلی setSelectedChime ویژگی selectedChime از ویژگی ChimeTrait را به‌روزرسانی کنید:

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

مدت زمان زنگ خارجی را تغییر دهید

مدت زمان زنگ زدن یک زنگ خارجی (بر حسب ثانیه) را می‌توان از طریق 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
  }
}

فعال کردن تم زنگوله

برخی از زنگ‌های در ممکن است زنگ‌هایی داشته باشند که فقط برای مدت محدودی در دسترس کاربران باشند. به عنوان مثال، زنگ‌های مخصوص تعطیلات. به این زنگ‌ها، زنگ‌های تم‌دار می‌گویند.

برای دیدن اینکه کدام تم‌های chime برای یک کاربر در دسترس هستند، یک فیلتر timebox ایجاد کنید و از آن برای فیلتر کردن نتایج دستور 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)
  }
}```