Przewodnik po dzwonku do drzwi na iOS

Typ urządzenia Dzwonek jest implementowany za pomocą 2 cech:PushAvStreamTransportTrait, która obsługuje transport strumieni audio i wideo za pomocą protokołów opartych na push, orazWebRtcLiveViewTrait, która umożliwia sterowanie transmisjami na żywo i funkcją talkback.

Przed użyciem jakichkolwiek funkcji lub próbą zaktualizowania atrybutów zawsze sprawdzaj, czy urządzenie obsługuje atrybuty i polecenia. Więcej informacji znajdziesz w artykule Sterowanie urządzeniami na iOS.

Typ urządzenia interfejsów Home API Cechy Przykładowa aplikacja w Swift Przypadek użycia

Dzwonek

GoogleDoorbellDeviceType

home.matter.6006.types.0113

Urządzenie uruchamiane przyciskiem na zewnątrz drzwi, które emituje sygnał dźwiękowy lub wizualny, używane do zwrócenia uwagi osoby znajdującej się po drugiej stronie drzwi. Dzwonki do drzwi mogą mieć funkcje transmisji na żywo z ułatwieniami dostępu, dwukierunkowego odtwarzania dźwięku lub wykrywania zdarzeń.

Wymagane cechy
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

Dzwonek

Rozpoczynanie transmisji na żywo

Aby rozpocząć transmisję na żywo, wyślij ciąg protokołu SDP (Session Description Protocol) do metody startLiveView(offerSdp:) cechy WebRtcLiveViewTrait, która zwraca 3 wartości:

  • SDP sesji.
  • Czas trwania sesji w sekundach.
  • Identyfikator sesji, który może służyć do przedłużenia lub zakończenia sesji.
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
  }
}

Przedłużanie transmisji na żywo

Transmisje na żywo mają z góry określony czas trwania, po którym wygasają. Aby wydłużyć czas trwania aktywnego strumienia, wyślij prośbę o przedłużenie za pomocą metody 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
  }
}

Włączanie i wyłączanie TalkBack

Aby uruchomić TalkBack, wywołaj metodę startTalkback(mediaSessionId:optionalArgsProvider:) cechy WebRtcLiveViewTrait. Aby zatrzymać, kliknij 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)")
  }
}

Włączanie i wyłączanie możliwości nagrywania

Aby włączyć funkcję nagrywania kamery, przekaż wartość TransportStatusEnum.Active do metody PushAvStreamTransportTrait cechy setTransportStatus(transportStatus:optionalArgsProvider:). Aby wyłączyć możliwość nagrywania, przekaż wartość TransportStatusEnum.Inactive. W poniższym przykładzie umieszczamy te wywołania w jednym wywołaniu, które używa Boolean, aby włączać i wyłączać możliwość nagrywania:

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

Włączenie lub wyłączenie funkcji nagrywania kamery jest równoznaczne z włączeniem lub wyłączeniem wideo z kamery. Gdy wideo z kamery jest włączone, kamera nagrywa (na potrzeby zdarzeń i powiązanych klipów).

Gdy funkcja nagrywania jest wyłączona (wideo z kamery jest wyłączone):

  • Kamera może nadal być widoczna jako online zgodnie z connectivityStatetypu urządzenia.
  • Nie można uzyskać dostępu do transmisji na żywo, a kamera nie wykrywa żadnych zdarzeń w chmurze.

Sprawdzanie, czy funkcja nagrywania jest włączona

Aby sprawdzić, czy funkcja nagrywania kamery jest włączona, sprawdź, czy są aktywne jakiekolwiek połączenia. Poniższy przykład definiuje 2 funkcje, które to umożliwiają:

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
}

Ustawienia dźwięku

Różnymi ustawieniami dźwięku kamery można sterować za pomocą interfejsów API Home.

Włączanie i wyłączanie mikrofonu

Aby włączyć lub wyłączyć mikrofon urządzenia, zaktualizuj atrybut microphoneMuted cechy CameraAvStreamManagementTrait za pomocą wbudowanej funkcji 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
  }
}

Włączanie i wyłączanie nagrywania dźwięku

Aby włączyć lub wyłączyć nagrywanie dźwięku na urządzeniu, zaktualizuj atrybut recordingMicrophoneMuted cechy CameraAvStreamManagementTrait za pomocą wbudowanej funkcji 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
  }
}

Dostosowywanie głośności głośnika

Aby dostosować głośność głośnika urządzenia, zaktualizuj atrybutspeakerVolumeLevel cechy CameraAvStreamManagementTrait za pomocą wbudowanej funkcjisetSpeakerVolumeLevel:

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

Inne ustawienia

Za pomocą interfejsów API Home można sterować różnymi innymi ustawieniami kamery.

Włączanie i wyłączanie widzenia w nocy

Aby włączyć lub wyłączyć widzenie w nocy w przypadku kamery, użyj TriStateAutoEnum, aby zaktualizować atrybut nightVision cechy CameraAvStreamManagementTrait za pomocą wbudowanej funkcji 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
  }
}

Zmiana jasności diody LED stanu

Aby zmienić jasność diody LED stanu, użyj ThreeLevelAutoEnum do zaktualizowania atrybutu statusLightBrightness cechy CameraAvStreamManagementTrait za pomocą wbudowanej funkcji setStatusLightBrightness:

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

Zmiana widocznego obszaru kamery

Widok z kamery jest taki sam jak w przypadku funkcji powiększania i kadrowania opisanej w artykule pomocy Powiększanie i ulepszanie obrazu z kamery Nest.

Obszar wyświetlania jest zdefiniowany w ViewportStruct, który zawiera 4 wartości używane jako współrzędne obszaru wyświetlania. Współrzędne są zdefiniowane w ten sposób:

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

Określanie wartości parametru ViewportStruct zależy od interfejsu aplikacji i implementacji kamery. Aby ustawić pole widzenia kamery, zaktualizuj atrybut viewport cechy CameraAvStreamManagementTrait za pomocą funkcji ViewportStruct, używając wbudowanej funkcji 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
    }
  }

}

Wygeneruj TransportOptionsStruct

Niektóre ustawienia wymagają modyfikacji właściwości w TransportOptionsStruct, które są następnie przekazywane do opcji transportu połączenia strumieniowego. W przypadku języka Swift tę strukturę należy wygenerować przed zaktualizowaniem jakichkolwiek właściwości.

Użyj tej funkcji pomocniczej, aby wygenerować strukturę do wykorzystania przy wprowadzaniu tych zmian ustawień:

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
}

Dostosowywanie czułości wybudzania urządzenia

Czułość wybudzania urządzenia służy do oszczędzania baterii poprzez zmniejszenie zakresu, w którym urządzenie może wykrywać aktywność, i wydłużenie czasu wybudzania po wykryciu tej aktywności.

W interfejsach Home API można to ustawić za pomocą właściwości motionSensitivity elementu triggerOptionstransportOptions urządzenia. Te opcje są zdefiniowane w PushAvStreamTransportTrait dla każdego urządzenia.

Czułość wybudzania można ustawić tylko na te wartości:

  • 1 = Niski
  • 5 = Średni
  • 10 = Wysoki

Proces aktualizacji polega na znalezieniu konfiguracji transportu dla aktywnych strumieni nagrywania za pomocą polecenia findTransport, a następnie zmodyfikowaniu konfiguracji za pomocą nowej wartości czułości za pomocą polecenia modifyPushTransport.

Polecenie modifyPushTransport wymaga przekazania pełnego TransportOptionsStruct, więc najpierw musisz skopiować istniejące wartości z bieżącej konfiguracji. Aby to zrobić, zapoznaj się z sekcją Generowanie TransportOptionsStruct dla funkcji pomocniczej.

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

Dostosowywanie maksymalnego czasu trwania zdarzenia

Maksymalna długość zdarzenia to czas, przez jaki kamera będzie nagrywać klip w przypadku zdarzenia. Za pomocą interfejsów Home API można skonfigurować dla każdego urządzenia te same długości, co w przypadku Google Home app (GHA), w odstępach sekund:

  • 10 sekund
  • 15 sekund
  • 30 sekund
  • 60 sekund (1 minuta)
  • 120 sekund (2 minuty)
  • 180 sekund (3 minuty)

W interfejsach Home API można to ustawić za pomocą właściwości motionTimeControl elementu triggerOptionstransportOptions urządzenia. Te opcje są zdefiniowane w PushAvStreamTransportTrait dla każdego urządzenia.

Aby zaktualizować konfigurację, znajdź konfigurację transportu dla aktywnych strumieni nagrywania za pomocą polecenia findTransport, a następnie zmodyfikuj konfigurację, podając nową wartość długości zdarzenia, za pomocą polecenia modifyPushTransport.

Polecenie modifyPushTransport wymaga przekazania pełnego TransportOptionsStruct, więc najpierw musisz skopiować istniejące wartości z bieżącej konfiguracji. Aby to zrobić, zapoznaj się z artykułem Generowanie TransportOptionsStruct dla funkcji pomocniczej.

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

Ustawienia dzwonka

Różnymi ustawieniami dzwonka można sterować za pomocą interfejsów Home API.

Zmienianie dźwięku gongu

Aby zmienić dźwięk dzwonka, najpierw pobierz listę dźwięków dzwonka zainstalowanych na urządzeniu, korzystając z atrybutu installedChimeSounds cechy ChimeTrait:

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

Następnie zaktualizuj atrybut selectedChime cechy ChimeTrait za pomocą wbudowanej funkcji setSelectedChime:

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

Używanie zewnętrznego dzwonka

Dzwonek można skonfigurować tak, aby korzystał z zewnętrznego dzwonka, np. mechanicznego dzwonka zainstalowanego w domu. Należy to skonfigurować podczas instalacji dzwonka, aby uniknąć potencjalnych uszkodzeń zewnętrznego dzwonka.

Aby wskazać typ zainstalowanego dzwonka zewnętrznego, użyj ExternalChimeType do zaktualizowania atrybutu externalChime cechy ChimeTrait za pomocą wbudowanej funkcji 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
  }
}

Zmiana czasu trwania zewnętrznego gongu

Czas dzwonienia zewnętrznego dzwonka w sekundach można skonfigurować za pomocą interfejsów Home API. Jeśli dzwonek zewnętrzny obsługuje czas trwania dzwonka, użytkownik może chcieć go skonfigurować.

Wartość ustawiona w tym miejscu zależy od specyfikacji zewnętrznego dzwonka i zalecanej długości dzwonka.

Aby zmienić czas trwania dzwonka zewnętrznego, zaktualizuj atrybut externalChimeDurationSeconds cechy ChimeTrait za pomocą wbudowanej funkcji setExternalChimeDurationSeconds:

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