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

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

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

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

زنگ در

Google Doorbell DeviceType

home.matter.6006.types.0113

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

ویژگی‌های مورد نیاز
google PushAvStreamTransportTrait
گوگل WebRtcLiveViewTrait

زنگ در

شروع پخش زنده

برای شروع پخش زنده، رشته‌ی پروتکل شرح جلسه (SDP) را به متد startLiveView(offerSdp:) از ویژگی WebRtcLiveViewTrait ارسال کنید، که سه مقدار را برمی‌گرداند:

  • SDP برای جلسه.
  • مدت زمان جلسه بر حسب ثانیه.
  • شناسه جلسه، که ممکن است برای تمدید یا خاتمه جلسه استفاده شود.
public func sendOffer(offerSdp: String) async throws
-> (answerSdp: String, mediaSessionId: String, liveViewDuration: TimeInterval)
{
  do {
    Logger.info("Sending StartLiveView command...")
    let response = try await liveViewTrait.startLiveView(
      offerSdp: offerSdp
    )
    Logger.info("Received StartLiveView response: \(response)")
    return (
      answerSdp: response.answerSdp,
      mediaSessionId: response.mediaSessionId,
      liveViewDuration: TimeInterval(response.liveSessionDurationSeconds)
    )
  } catch {
    Logger.error("Failed to send StartLiveView command: \(error)")
    throw error
  }
}

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

پخش زنده (Livestream) دارای مدت زمان از پیش تعیین شده‌ای است که پس از آن منقضی می‌شود. برای افزایش مدت زمان یک پخش زنده فعال، با استفاده از متد extendLiveView(mediaSessionId:optionalArgsProvider:) درخواست تمدید پخش را ارسال کنید:

public func extendLiveView(mediaSessionId: String) async throws {
  do {
    Logger.info("Extending live view...")
    let extendedDuration = try await liveViewTrait.extendLiveView(mediaSessionId: mediaSessionId)
    Logger.info("Extended live view for \(extendedDuration.liveSessionDurationSeconds) seconds.")
  } catch {
    Logger.error("Failed to extend live view: \(error)")
    throw error
  }
}

شروع و توقف تاک‌بک

برای شروع talkback، متد startTalkback(mediaSessionId:optionalArgsProvider:) از ویژگی WebRtcLiveViewTrait را فراخوانی کنید. برای توقف آن، stopTalkback(mediaSessionId:) استفاده کنید.

public func toggleTwoWayTalk(isOn: Bool, mediaSessionId: String) async throws {
  do {
    Logger.info("Toggling twoWayTalk to \(isOn ? "ON" : "OFF")...")
    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 {
    Logger.error("PushAvStreamTransportTrait not found.")
    return
  }
  Task {
    do {
      try await pushAvStreamTransportTrait.setTransportStatus(
        transportStatus: isOn ? .active : .inactive)
      if isOn {
        do {
          self.player = try self.createWebRtcPlayer()
        } catch {
          Logger.error("Failed to initialize WebRtcPlayer: \(error)")
          self.uiState = .disconnected
          return
        }
        await self.player?.initialize()
        self.uiState = .live
      } else {
        self.player = nil
        self.uiState = .off
      }
    } catch {
      Logger.error("Failed to toggle onOff: \(error)")
    }
  }
}

فعال یا غیرفعال کردن قابلیت ضبط دوربین، همانند روشن یا خاموش کردن فیلم‌برداری دوربین است. وقتی فیلم‌برداری دوربین فعال است، در حال ضبط است (برای رویدادها و کلیپ‌های مرتبط).

وقتی قابلیت ضبط غیرفعال است (فیلمبرداری دوربین خاموش است):

  • دوربین همچنان می‌تواند بر اساس connectivityState نوع دستگاه، آنلاین نشان داده شود.
  • دسترسی به پخش زنده امکان‌پذیر نیست و دوربین نیز هیچ رویداد ابری را تشخیص نمی‌دهد.

بررسی کنید که آیا قابلیت ضبط فعال است یا خیر

برای تعیین اینکه آیا قابلیت ضبط دوربین فعال است یا خیر، بررسی کنید که آیا اتصالات فعال هستند یا خیر. مثال زیر دو تابع برای انجام این کار تعریف می‌کند:

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

تنظیمات صوتی

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

تنظیمات دیگر

تنظیمات مختلف دوربین دیگر را می‌توان از طریق 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های خانه کنترل کرد.

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

برای تغییر صدای زنگ در، ابتدا لیست صداهای زنگی که روی دستگاه نصب شده‌اند را با استفاده از ویژگی 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
  }
}