Guida al dispositivo campanello per iOS

Il tipo di dispositivo Campanello viene implementato utilizzando due tratti: PushAvStreamTransportTrait, che gestisce il trasporto di stream audio e video utilizzando protocolli basati su push e WebRtcLiveViewTrait, che offre la possibilità di controllare le live streaming e la funzionalità TalkBack.

Prima di utilizzare qualsiasi funzionalità o tentare di aggiornare gli attributi, controlla sempre il supporto di attributi e comandi per un dispositivo. Per ulteriori informazioni, consulta Controllare i dispositivi su iOS.

Tipo di dispositivo delle API Home Tratti App di esempio Swift Caso d'uso

Campanello

GoogleDoorbellDeviceType

home.matter.6006.types.0113

Un dispositivo azionato da un pulsante all'esterno di una porta che emette un segnale acustico e/o visivo, utilizzato per richiedere l'attenzione di una persona che si trova da qualche parte dall'altro lato della porta. I campanelli possono includere live streaming accessibili, comunicazione bidirezionale o eventi di rilevamento.

Tratti richiesti
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

Campanello

Visualizzare le informazioni di base su un dispositivo

La caratteristica BasicInformation include informazioni quali nome del fornitore, ID fornitore, ID prodotto, nome del prodotto (incluse le informazioni sul modello), versione software e numero di serie di un dispositivo:

// [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]

Controllare la connettività di un dispositivo

La connettività di un dispositivo viene effettivamente controllata a livello di tipo di dispositivo perché alcuni dispositivi supportano più tipi di dispositivi. Lo stato restituito è una combinazione degli stati di connettività per tutte le caratteristiche del dispositivo.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Uno stato di partiallyOnline può essere osservato nel caso di tipi di dispositivi misti quando non è presente una connettività a internet. Matter standard potrebbero essere ancora online a causa del routing locale, ma le caratteristiche basate sul cloud saranno offline.

Avviare un live streaming

Per avviare un live streaming, invia la stringa SDP (Session Description Protocol) al metodo WebRtcLiveViewTrait dell'attributo startLiveView(offerSdp:), che restituisce tre valori:

  • L'SDP per la sessione.
  • La durata della sessione in secondi.
  • L'ID sessione, che può essere utilizzato per estendere o terminare la sessione.
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
  }
}

Estendere un live streaming

I live streaming hanno una durata preimpostata dopo la quale scadono. Per estendere la durata di uno stream attivo, invia una richiesta di estensione utilizzando il metodo 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
  }
}

Avviare e interrompere TalkBack

Per avviare TalkBack, chiama il metodo startTalkback(mediaSessionId:optionalArgsProvider:) del tratto WebRtcLiveViewTrait. Per interrompere, utilizza 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)")
  }
}

Attivare e disattivare la funzionalità di registrazione

Per attivare la funzionalità di registrazione della videocamera, passa TransportStatusEnum.Active al metodo PushAvStreamTransportTrait dell'attributo setTransportStatus(transportStatus:optionalArgsProvider:). Per disattivare la funzionalità di registrazione, passa TransportStatusEnum.Inactive. Nel seguente esempio, racchiudiamo queste chiamate in una singola chiamata che utilizza un Boolean per attivare/disattivare la funzionalità di registrazione:

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

L'attivazione o la disattivazione della funzionalità di registrazione della videocamera equivale ad accendere o spegnere il video della videocamera. Quando il video di una videocamera è attivo, la videocamera registra (ai fini degli eventi e dei clip correlati).

Quando la funzionalità di registrazione è disattivata (il video della videocamera è spento):

  • La videocamera può comunque essere visualizzata come online in base all'connectivityState del tipo di dispositivo.
  • Non è possibile accedere al live streaming e la videocamera non rileva eventi sul cloud.

Controllare se la funzionalità di registrazione è attiva

Per determinare se la funzionalità di registrazione di una videocamera è attiva, controlla se sono attive connessioni. L'esempio seguente definisce due funzioni per farlo:

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
}

Impostazioni della batteria

È possibile controllare varie impostazioni della batteria tramite le API Home.

Impostare la preferenza di utilizzo della batteria

L'impostazione del bilanciamento energetico consente di configurare il compromesso tra durata della batteria e prestazioni di un dispositivo. Puoi creare diversi profili batteria, ad esempio "Esteso", "Bilanciato" e "Prestazioni", e passare da uno all'altro.

Questa funzionalità viene implementata aggiornando l'attributo currentEnergyBalance del tratto EnergyPreference. L'attributo accetta un indice intero che corrisponde a un profilo specifico definito nell'elenco energyBalances del dispositivo (ad esempio, 0 per EXTENDED, 1 per BALANCED e 2 per PERFORMANCE).

Un valore null per currentEnergyBalance indica che il dispositivo utilizza un profilo personalizzato. Questo è uno stato di sola lettura.

Di seguito è riportato un esempio di struttura che verrà utilizzata dall'attributo currentEnergyBalance, seguito dallo snippet di codice effettivo che utilizza l'attributo.

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

Attivare il risparmio energetico automatico

Per configurare questa funzionalità, aggiorna l'attributo currentLowPowerModeSensitivity del tratto EnergyPreference. Questo attributo utilizza un indice per selezionare un livello di sensibilità, dove 0 in genere rappresenta Disabled e 1 rappresenta Enabled o Automatic.

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

Ottenere lo stato di ricarica della batteria

Per ottenere lo stato di ricarica attuale del dispositivo (in carica, completamente carico o non in carica), utilizza l'attributo batChargeState del tratto 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"
}

Ottenere il livello della batteria

Per ottenere il livello attuale della batteria, utilizza l'attributo batChargeLevel del tratto PowerSource. Il livello è OK, Warning (basso) o 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"
}

Recuperare la fonte di alimentazione

Per determinare la fonte di alimentazione utilizzata dal dispositivo, utilizza gli attributi BatPresent e wiredPresent del tratto PowerSource.

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

Impostazioni audio

È possibile controllare varie impostazioni audio tramite le API Home.

Attivare o disattivare il microfono

Per attivare o disattivare il microfono del dispositivo, aggiorna l'attributo microphoneMuted del tratto CameraAvStreamManagementTrait utilizzando la funzione setMicrophoneMuted integrata:

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

Attivare o disattivare la registrazione audio

Per attivare o disattivare la registrazione audio per il dispositivo, aggiorna l'attributo recordingMicrophoneMuted del tratto CameraAvStreamManagementTrait utilizzando la funzione setRecordingMicrophoneMuted integrata:

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

Regolare il volume dello speaker

Per regolare il volume dello speaker del dispositivo, aggiorna l'attributo speakerVolumeLevel del tratto CameraAvStreamManagementTrait utilizzando la funzione setSpeakerVolumeLevel integrata:

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

Altre impostazioni

Varie altre impostazioni possono essere controllate tramite le API Home.

Attivare o disattivare la visione notturna

Per attivare o disattivare la visione notturna per la videocamera, utilizza TriStateAutoEnum per aggiornare l'attributo nightVision del tratto CameraAvStreamManagementTrait utilizzando la funzione setNightVision integrata:

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

Modificare la luminosità del LED di stato

Per modificare la luminosità del LED di stato, utilizza ThreeLevelAutoEnum per aggiornare l'attributo statusLightBrightness del tratto CameraAvStreamManagementTrait utilizzando la funzione setStatusLightBrightness integrata:

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

Modificare il viewport della videocamera

La finestra della videocamera è la stessa della funzionalità Zoom e ritaglio descritta nell'articolo del Centro assistenza Aumentare lo zoom e migliorare i video della videocamera Nest.

La finestra viene definita in un ViewportStruct che contiene quattro valori, che vengono utilizzati come coordinate della finestra. Le coordinate sono definite come:

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

La determinazione dei valori per ViewportStruct dipende dall'interfaccia utente di un'app e dall'implementazione della fotocamera. A un livello molto base, per impostare la visualizzazione del video della videocamera, aggiorna l'attributo viewport del tratto CameraAvStreamManagementTrait con un ViewportStruct, utilizzando la funzione setViewport integrata.

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

}

Genera una TransportOptionsStruct

Alcune impostazioni richiedono modifiche alle proprietà in un TransportOptionsStruct, che viene poi passato alle opzioni di trasporto di una connessione di streaming. Per Swift, questa struttura deve essere generata prima di aggiornare qualsiasi proprietà.

Utilizza questa funzione helper per generare lo struct da utilizzare con le seguenti modifiche alle impostazioni:

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
}

Regolare la sensibilità alla riattivazione del dispositivo

La sensibilità di riattivazione del dispositivo viene utilizzata per risparmiare batteria diminuendo il raggio in cui il dispositivo può rilevare l'attività e aumentando il tempo di riattivazione dopo aver rilevato l'attività.

Nelle API Home, questa impostazione può essere configurata utilizzando la proprietà motionSensitivity di triggerOptions in transportOptions del dispositivo. Queste opzioni sono definite nell'attributo PushAvStreamTransportTrait per ogni dispositivo.

La sensibilità al risveglio può essere impostata solo sui seguenti valori:

  • 1 = Basso
  • 5 = Media
  • 10 = Alto

La procedura di aggiornamento consiste nel trovare la configurazione di trasporto per i flussi di registrazione attivi utilizzando il comando findTransport, quindi modificare la configurazione con il nuovo valore di sensibilità utilizzando il comando modifyPushTransport.

Il comando modifyPushTransport richiede il passaggio dell'intero TransportOptionsStruct, quindi devi prima copiare i valori esistenti dalla configurazione attuale. Per farlo, consulta Generare un TransportOptionsStruct per una funzione helper.

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

Regolare la durata massima degli eventi

La durata massima degli eventi è il periodo di tempo per cui la videocamera registrerà un clip per un evento. Tramite le API Home, questa impostazione può essere configurata, per dispositivo, con le stesse durate che si ottengono tramite Google Home app (GHA), a intervalli di secondi:

  • 10 secondi
  • 15 secondi
  • 30 secondi
  • 60 secondi (1 minuto)
  • 120 secondi (2 minuti)
  • 180 secondi (3 minuti)

Nelle API Home, questa impostazione può essere configurata utilizzando la proprietà motionTimeControl di triggerOptions in transportOptions del dispositivo. Queste opzioni sono definite nell'attributo PushAvStreamTransportTrait per ogni dispositivo.

La procedura di aggiornamento consiste nel trovare la configurazione di trasporto per i flussi di registrazione attivi utilizzando il comando findTransport, quindi modificare la configurazione con il nuovo valore della durata dell'evento utilizzando il comando modifyPushTransport.

Il comando modifyPushTransport richiede il passaggio dell'intero TransportOptionsStruct, quindi devi prima copiare i valori esistenti dalla configurazione attuale. Per farlo, consulta Generare un TransportOptionsStruct per una funzione helper.

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

Impostazioni del cicalino

È possibile controllare varie impostazioni del suono del campanello tramite le API Home.

Modificare il suono del cicalino

Per modificare il suono della suoneria del campanello, recupera prima l'elenco dei suoni della suoneria installati sul dispositivo utilizzando l'attributo installedChimeSounds del tratto ChimeTrait:

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

Quindi, aggiorna l'attributo selectedChime del tratto ChimeTrait utilizzando la funzione integrata setSelectedChime:

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

Utilizzare un cicalino esterno

Il campanello può essere configurato per utilizzare un cicalino esterno, ad esempio una campana meccanica installata all'interno della casa. Questa impostazione deve essere configurata durante l'installazione del campanello per evitare potenziali danni al cicalino esterno.

Per indicare il tipo di campanello esterno installato, utilizza ExternalChimeType per aggiornare l'attributo externalChime del tratto ChimeTrait utilizzando la funzione setExternalChime integrata:

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

Modificare la durata del suono del cicalino esterno

La durata, in secondi, del suono di un campanello esterno può essere configurata tramite le API Home. Se il suono esterno supporta una durata, un utente potrebbe volerla configurare.

Il valore impostato qui dipende dalle specifiche del cicalino esterno e dalla durata consigliata del suono.

Per modificare la durata del suono di avviso esterno, aggiorna l'attributo externalChimeDurationSeconds del tratto ChimeTrait utilizzando la funzione setExternalChimeDurationSeconds integrata:

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

Attivare un tema per il suono di notifica

Alcuni campanelli potrebbero avere suonerie disponibili solo per un periodo di tempo limitato. Ad esempio, suoni specifici per le festività. Questi si chiamano temi di notifica.

Per vedere quali temi di suono sono disponibili per un utente, crea un filtro timebox e utilizzalo per filtrare i risultati del comando getAvailableThemes dall'attributo ChimeThemes. Viene restituito un elenco di temi disponibili, inclusi i nomi dei temi.

Il seguente esempio mostra come filtrare l'elenco. Un tema è considerato attivo se l'ora corrente rientra nell'intervallo tra l'ora di inizio e l'ora di fine (rispettivamente i valori startTimeSeconds e endTimeSeconds). Se non è impostata un'ora di inizio, viene considerata attiva dall'inizio dei tempi. Se non viene impostata un'ora di fine, la regola rimane attiva a tempo indeterminato. Se mancano entrambi, il tema è sempre attivo.

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 <= currentDateTime
      && chimeTheme.endTimeSeconds ?? UInt64.max >= currentDateTime
    {
      self.chimeThemeSettings.append(chimeTheme.name)
    }
  }
}

Una volta ottenuto il nome del tema che vuoi, ad esempio Christmas, puoi selezionarlo utilizzando la funzione setSelectedTimeboxedThemeName() nella caratteristica ChimeThemes ChimeThemes.

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