Guide de l'appareil Doorbell pour iOS

Le type d'appareil "Sonnette" est implémenté à l'aide de trois traits : PushAvStreamTransportTrait, qui gère le transport des flux audio et vidéo à l'aide de protocoles de type push, WebRtcLiveViewTrait, qui permet de contrôler les flux en direct et la fonctionnalité de communication bidirectionnelle, et CameraSnapshotTrait, qui fournit des instantanés d'aperçu mis en cache et des captures d'instantanés en direct.

Assurez-vous toujours qu'un appareil prend en charge les attributs et les commandes nécessaires avant d'utiliser une fonctionnalité ou de tenter de mettre à jour des attributs. Pour en savoir plus, consultez Contrôler les appareils suriOS.

Type d'appareil pour les API Home Caractéristiques Application exemple Swift Cas d'utilisation

Sonnette

GoogleDoorbellDeviceType

home.matter.6006.types.0113

Appareil actionné par un bouton situé à l'extérieur d'une porte, qui émet un signal sonore et/ou visuel, utilisé pour attirer l'attention d'une personne se trouvant de l'autre côté de la porte. Les sonnettes peuvent proposer un accès à des flux en direct, une fonctionnalité de communication bidirectionnelle ou générer des événements de détection.

Caractéristiques requises
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

Sonnette

Obtenir des informations de base sur un appareil

   Implémenté dans l'application exemple pour iOS   

Le trait BasicInformation inclut des informations telles que le nom du fournisseur, l'ID du fournisseur, l'identifiant produit, le nom du produit (y compris les informations sur le modèle) et la version logicielle d'un appareil :

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!

Obtenir le numéro de série

   Implémenté dans l'application exemple pour iOS   

Pour obtenir le numéro de série de l'appareil, utilisez la commande GetSerialNumber de la caractéristique ExtendedBasicInformation. L'exemple montre comment enregistrer le numéro de série dans une variable nommée serialNumber :

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

Réponses rapides

La fonctionnalité Réponses rapides permet à l'utilisateur d'envoyer un message prédéfini à une sonnette.

Cette fonctionnalité n'est disponible que sur les sonnettes. La liste des messages prédéfinis est disponible pour l'application partenaire, qui peut les présenter à l'utilisateur pour qu'il fasse son choix. Les messages prédéfinis ne sont pas modifiables par l'utilisateur.

Les réponses rapides sont implémentées via le trait PresetMessage.

Diffuser un message prédéfini

Pour lire un message prédéfini, appelez la méthode playPresetMessage en lui transmettant l'une des valeurs de chaîne de la propriété 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)")
    }
}

Définir la langue parlée

Définir la langue parlée

Définissez la langue parlée active d'un appareil sur des paramètres régionaux spécifiques (par exemple, "en_US") à l'aide de la méthode setActiveLocale du trait LocalizationConfiguration.

// Setting the active language
// Assuming localizationConfigurationTrait: Matter.LocalizationConfigurationTrait
let selectedLocale = "en_US"
try await localizationConfigurationTrait.update {
    $0.setActiveLocale(selectedLocale)
}

Obtenir l'heure du dernier contact de l'appareil avec le cloud

Pour trouver la dernière fois que l'appareil a été en contact avec le cloud, utilisez l'attribut lastContactTimestamp du trait ExtendedGeneralDiagnostics :

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

Paramètres du type de support de la caméra

Le trait Mount contient les paramètres de montage de la caméra et les informations d'état. Vous pouvez lire des attributs tels que l'état d'installation, le type de détection et le nom du type d'installation. En outre, vous pouvez utiliser la caractéristique Mount pour remplacer la configuration de type d'installation par défaut.

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

Vérifier la connectivité d'un appareil

La connectivité d'un appareil est en fait vérifiée au niveau du type d'appareil, car certains appareils sont compatibles avec plusieurs types d'appareils. L'état renvoyé est une combinaison des états de connectivité de tous les traits de cet appareil.

let doorbellConnectivity = doorbellDeviceType.metadata.sourceConnectivity.connectivityState

Un état partiallyOnline peut être observé dans le cas de types d'appareils mixtes lorsqu'il n'y a pas de connectivité Internet. Les caractéristiques standards Matter peuvent toujours être en ligne en raison du routage local, mais les caractéristiques dans le cloud seront hors connexion.

Obtenir l'adresse IP de l'appareil

Pour trouver l'adresse IP de l'appareil, utilisez l'attribut networkInterfaces de GeneralDiagnosticsTrait. Les adresses sont renvoyées sous forme d'objets Data, que vous pouvez formater en chaînes IPv4 ou IPv6 standards à l'aide du framework 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
}

Lancer un flux en direct

   Implémenté dans l'application exemple pour iOS   

Pour lancer un flux en direct, envoyez la chaîne SDP (Session Description Protocol) à la méthode startLiveView(offerSdp:) du trait WebRtcLiveViewTrait, qui renvoie trois valeurs :

  • SDP de la session
  • Durée de la session en secondes
  • ID de la session, qui peut être utilisé pour la prolonger ou y mettre fin
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
  }
}

Prolonger un flux en direct

   Implémenté dans l'application exemple pour iOS   

Les flux en direct ont une durée prédéfinie au terme de laquelle ils expirent. Pour prolonger la durée d'un flux actif, utilisez la méthode 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
  }
}

Démarrer et arrêter la conversation bidirectionnelle

   Implémenté dans l'application exemple pour iOS   

Pour démarrer la conversation bidirectionnelle, appelez la méthode startTalkback(mediaSessionId:optionalArgsProvider:) du trait WebRtcLiveViewTrait. Pour arrêter, utilisez 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)")
  }
}

Gérer la diffusion en direct

   Implémenté dans l'application exemple pour iOS   

L'ajustement de la qualité de la diffusion en direct est utile pour optimiser l'utilisation de la bande passante en fonction du contexte de visionnage du client (par exemple, passer à une résolution inférieure lors de l'affichage d'une vignette d'aperçu plus petite, d'un mode Grille ou d'un mode Picture-in-picture).

La modification dynamique de la qualité à l'aide de la caractéristique WebRtcLiveView gère spécifiquement la résolution de la session de diffusion en direct active sur un client particulier. Il ne s'agit pas de configurer un paramètre d'utilisation de la bande passante à l'échelle de l'appareil directement sur celui-ci, ce qui affecterait tous les spectateurs simultanés et la qualité des enregistrements vidéo historiques enregistrés dans le cloud.

L'exemple suivant montre comment récupérer et mettre à jour la qualité de la diffusion en direct pour un appareil :

  • Récupérer les options de qualité compatibles : obtenez les résolutions de streaming disponibles compatibles avec l'appareil. Le code interroge le trait WebRtcLiveView pour exposer les qualités de flux compatibles sous la forme d'une liste de valeurs QualityHint (telles que .sd, .hd, .fhd, .qhd ou .uhd) à l'aide de la propriété supportedQualityHints.

  • Modifier la qualité de la diffusion en direct : appliquez un QualityHint sélectionné pour modifier la résolution de la diffusion en direct active (par exemple, passer de la définition standard à la haute définition). La fonction updateQualityHint utilise la méthode changeLiveViewQuality de la caractéristique WebRtcLiveView pour appliquer la configuration QualityHint sélectionnée à la session multimédia active.

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

Activer et désactiver la capacité d'enregistrement

Pour activer la capacité d'enregistrement de la caméra, transmettez TransportStatusEnum.Active à la méthode setTransportStatus(transportStatus:optionalArgsProvider:) du trait PushAvStreamTransportTrait. Pour désactiver la capacité d'enregistrement, transmettez-lui TransportStatusEnum.Inactive. Dans l'exemple suivant, nous encapsulons ces appels dans un seul appel qui utilise un Boolean pour activer ou désactiver la capacité d'enregistrement :

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

Activer ou désactiver la capacité d'enregistrement de la caméra revient à activer ou désactiver la vidéo de la caméra. Lorsque la vidéo d'une caméra est activée, elle enregistre (pour les événements et les extraits associés).

Lorsque la capacité d'enregistrement est désactivée (la vidéo de la caméra est désactivée) :

  • La caméra peut toujours apparaître comme étant en ligne, conformément à la connectivityState du type d'appareil.
  • Le flux en direct n'est pas accessible et la caméra ne détecte aucun événement cloud.

Vérifier si la capacité d'enregistrement est activée

Pour savoir si la capacité d'enregistrement d'une caméra est activée, vérifiez si des connexions sont actives. L'exemple suivant définit deux fonctions pour ce faire :

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
}

Récupérer des instantanés de caméra

   Implémenté dans l'application exemple pour iOS   

Utilisez la caractéristique CameraSnapshot pour récupérer des instantanés d'images statiques à partir d'une caméra. Ces instantanés sont utiles dans plusieurs scénarios :

  • En tant que tuile d'espace réservé dans l'UI pendant le chargement d'un flux en direct WebRTC.
  • Sous la forme d'une image d'aperçu statique qui se transforme en diffusion en direct lorsque l'utilisateur interagit avec elle.
  • Comme canevas d'arrière-plan pour dessiner et configurer des zones d'activité personnalisées.

Le trait CameraSnapshot propose deux façons de récupérer des instantanés, selon que vous avez besoin d'un instantané mis en cache pour un rendu rapide ou d'un instantané en direct à la demande.

Obtenir un instantané d'aperçu mis en cache

Un instantané d'aperçu est une image mise en cache que le SDK peut récupérer sans réactiver la caméra. Il s'agit de la méthode la plus rapide pour récupérer une image statique. Elle est idéale pour les pages de présentation de la caméra ou les grilles de tableau de bord.

Pour obtenir l'instantané d'aperçu, lisez l'attribut de trait preview_image_url :

guard let cameraSnapshotTrait = deviceType.traits[
  Google.CameraSnapshotTrait.self
] else {
  print("CameraSnapshot trait not supported on this device.")
  return
}

if let previewImageUrlString = cameraSnapshotTrait
  .attributes.preview_image_url,
   let url = URL(string: previewImageUrlString) {
  // Load the preview image from the URL
}

En fonction de la configuration et de l'activité de la caméra, l'URL d'aperçu pointe vers une image mise en cache générée à partir d'une séquence vidéo récente (la première image I du dernier fragment vidéo) ou d'un instantané importé régulièrement par la caméra.

Pour indiquer l'actualisation de l'image, le cloud Google Home intègre un en-tête X-Home-Image-Captured-At dans l'image JPEG/PNG diffusée, au format UTC. Vous pouvez analyser cet en-tête côté client pour afficher l'âge de l'instantané dans une application.

Obtenir un instantané en direct à la demande

Pour les parcours utilisateur qui nécessitent la vue en direct actuelle de la caméra (par exemple, la configuration de zones d'activité), vous pouvez demander un instantané en direct. Le déclenchement d'un instantané en direct indique à la caméra de s'activer, de capturer une nouvelle image et de l'importer dans le cloud.

Pour demander un instantané en direct, utilisez la commande getLiveSnapshot() :

do {
  let response = try await cameraSnapshotTrait.getLiveSnapshot()
  let snapshotUrlString = response.snapshot_url

  if let url = URL(string: snapshotUrlString) {
    // Load the live snapshot image from the URL
  }
} catch {
  print("Failed to get live snapshot: \(error)")
}

Authentifier les requêtes d'instantané

   Implémenté dans l'application exemple pour iOS   

Toutes les URL d'instantanés pointent vers des contenus multimédias sécurisés et nécessitent un jeton OAuth 2.0 pour le champ d'application des API Home v2. Pour télécharger et afficher les images, le jeton OAuth doit être injecté en tant que jeton de support dans l'en-tête Authorization de votre requête HTTP.

L'exemple suivant montre comment configurer une requête réseau sécurisée pour télécharger un instantané :

import UIKit

func loadSnapshotImage(from url: URL, home: Home) async -> UIImage? {
  do {
    // 1. Retrieve the OAuth access token from the Home APIs SDK
    let (accessToken, _) = try await home.permissions.authorization()

    // 2. Configure the HTTP GET request with the Bearer token
    var request = URLRequest(url: url)
    request.setValue(
      "Bearer \(accessToken)",
      forHTTPHeaderField: "Authorization"
    )

    // 3. Fetch the image data
    let (data, _) = try await URLSession.shared.data(for: request)
    return UIImage(data: data)
  } catch {
    print("Error loading snapshot image: \(error)")
    return nil
  }
}

Paramètres de batterie

Vous pouvez contrôler différents paramètres de la batterie via les API Home.

Définir la préférence d'utilisation de la batterie

Le réglage de l'équilibre énergétique vous permet de configurer le compromis entre l'autonomie de la batterie et les performances d'un appareil. Vous pouvez créer différents profils de batterie, tels que "Prolongé", "Équilibré" et "Performances", et passer de l'un à l'autre.

Cette fonctionnalité est implémentée en mettant à jour l'attribut currentEnergyBalance du trait EnergyPreference. L'attribut accepte un index entier qui correspond à un profil spécifique défini dans la liste energyBalances de l'appareil (par exemple, 0 pour EXTENDED, 1 pour BALANCED et 2 pour PERFORMANCE).

Une valeur null pour currentEnergyBalance indique que l'appareil utilise un profil personnalisé. Il s'agit d'un état en lecture seule.

Voici un exemple de structure que l'attribut currentEnergyBalance utilisera, suivi de l'extrait de code réel qui utilise l'attribut.

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

Activer l'économiseur de batterie automatique

   Implémenté dans l'application exemple pour iOS   

Pour configurer cette fonctionnalité, mettez à jour l'attribut currentLowPowerModeSensitivity du trait EnergyPreference. Cet attribut utilise un index pour sélectionner un niveau de sensibilité, où 0 représente généralement Disabled et 1 représente Enabled ou Automatic.

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

Obtenir l'état de charge de la batterie

   Implémenté dans l'application exemple pour iOS   

Pour obtenir l'état de charge actuel de l'appareil (en charge, complètement chargé ou non en charge), utilisez l'attribut batChargeState du trait 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"
}

Obtenir le niveau de batterie

Pour obtenir le niveau de batterie actuel, utilisez l'attribut batChargeLevel du trait PowerSource. Le niveau est OK, Warning (faible) ou 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"
}

Obtenir la source d'alimentation

Pour déterminer la source d'alimentation utilisée par l'appareil, utilisez les attributs BatPresent et wiredPresent du trait PowerSource.

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

Vérifier si la batterie doit être remplacée

L'attribut batReplaceability indique si la batterie est non remplaçable, remplaçable par l'utilisateur ou remplaçable en usine.

Si la batterie est remplaçable, l'attribut batReplacementNeeded du trait PowerSource vous indique si elle doit être remplacée.

// Get the battery replacement status
var batteryStatus = powerSourceTrait.attributes.batReplacementNeeded

if batteryStatus {
  print("Replace the battery.")
}

Lorsque la batterie peut être remplacée par l'utilisateur, batReplacementDescription décrit la batterie, y compris des informations telles que le facteur de forme, la chimie et le fabricant préféré.

Paramètres audio

Vous pouvez contrôler différents paramètres audio via les API Home.

Activer ou désactiver le micro

Pour activer ou désactiver le micro de l'appareil, mettez à jour l'attribut microphoneMuted du trait CameraAvStreamManagementTrait à l'aide de la fonction setMicrophoneMuted intégrée :

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

Activer ou désactiver l'enregistrement audio

Pour activer ou désactiver l'enregistrement audio de l'appareil, mettez à jour l'attribut recordingMicrophoneMuted du trait CameraAvStreamManagementTrait à l'aide de la fonction setRecordingMicrophoneMuted intégrée :

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

Régler le volume de l'enceinte

Pour régler le volume du haut-parleur de l'appareil, mettez à jour l'attribut speakerVolumeLevel du trait CameraAvStreamManagementTrait à l'aide de la fonction setSpeakerVolumeLevel intégrée :

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

Paramètres des zones d'activité

   Implémenté dans l'application exemple pour iOS   

Le trait ZoneManagement fournit une interface permettant de gérer les régions d'intérêt personnalisées (zones d'activité) sur les caméras et les sonnettes. Ces zones permettent de filtrer la détection d'événements (comme les mouvements de personnes ou de véhicules) dans des zones spécifiques du champ de vision de l'appareil.

Les zones d'activité sont configurées par l'utilisateur dans une application partenaire, ce qui lui permet de dessiner des zones sur des zones spécifiques du champ de vision de la caméra. Ces zones définies par l'utilisateur sont ensuite traduites dans les structures utilisées par ce trait. Pour en savoir plus sur le fonctionnement des zones d'activité, consultez Configurer et utiliser des zones d'activité.

Les zones d'activité sont généralement définies à l'aide de coordonnées cartésiennes 2D. Le trait fournit l'élément TwoDCartesianVertexStruct pour les sommets et l'élément TwoDCartesianZoneStruct pour la définition de la zone (nom, sommets, couleur et utilisation).

Vérifier les zones d'activité

Pour afficher les zones d'activité, vérifiez l'attribut zones de la caractéristique ZoneManagement.

let zoneManagementTrait: Google.ZoneManagementTrait

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

Ajouter une zone d'activité

Pour créer une zone, utilisez la commande createTwoDCartesianZone. Cette commande utilise un TwoDCartesianZoneStruct, qui définit le nom, les sommets, la couleur et l'utilisation de la zone.

L'exemple suivant montre comment créer une zone nommée "Porche" avec quatre sommets, de couleur saumon (#F439A0), et utilisée pour la détection de mouvement.

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

Mettre à jour une zone d'activité

Pour mettre à jour une zone existante, utilisez la commande updateTwoDCartesianZone. Cette commande nécessite le zoneId et le TwoDCartesianZoneStruct mis à jour.

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16
let zone: Google.ZoneManagementTrait.TwoDCartesianZoneStruct

do {
  _ = try await zoneManagementTrait.updateTwoDCartesianZone(
        zoneID: zoneID, zone: zone)
} catch {
  // Error
}

Supprimer une zone d'activité

Pour supprimer une zone, utilisez la commande removeZone avec l'élément zoneId spécifique.

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16

do {
  _ = try await zoneManagementTrait.removeZone(zoneID: zoneID)
} catch {
  // Error
}

Déclencheurs d'événements sonores

Le trait AvStreamAnalysis fournit une interface permettant de gérer les déclencheurs de détection d'événements sur les caméras et les sonnettes. Alors que les déclencheurs visuels (comme les personnes ou les véhicules) peuvent être spécifiques à une zone, les déclencheurs sonores sont généralement configurés au niveau de l'appareil.

Les types de déclencheurs suivants sont disponibles pour la détection des sons avec EventTriggerTypeEnum :

Mode Valeur d'énumération Description
Son Sound Détection générale des sons.
Voix PersonTalking Détecte la voix.
Aboiement de chien DogBark Détecte les vocalisations canines.
Bris de verre GlassBreak Détecte le bruit de verre brisé.
Détecteur de fumée SmokeAlarm Détecte les détecteurs de fumée, souvent reconnus par le signal sonore T3 (trois bips courts suivis d'une pause).
Alarme monoxyde carbone CoAlarm Détecte les alarmes de monoxyde de carbone (CO), généralement reconnaissables à leur signal sonore T4 (quatre bips courts suivis d'une pause).

Vérifier l'état de la détection des sons

Pour afficher l'état actuel de la détection des sons pour l'utilisateur, vous devez vérifier ce que l'appareil prend en charge et ce qui est activé par le matériel de l'appareil. Les deux attributs à vérifier sont les suivants :

Dans le développement iOS, vous accédez généralement à la caractéristique AvStreamAnalysis à partir de l'appareil pour lire ces attributs.

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

Mettre à jour l'ensemble des déclencheurs activés

Pour mettre à jour l'ensemble des déclencheurs activés, utilisez la commande SetOrUpdateEventDetectionTriggers, qui utilise une liste de structures 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
)

Modes d'enregistrement

   Implémenté dans l'application exemple pour iOS   

Le trait RecordingMode fournit une interface permettant de gérer le comportement d'enregistrement vidéo et d'image sur les caméras et les sonnettes. Elle permet aux utilisateurs de choisir entre l'enregistrement continu, l'enregistrement en cas d'événement ou la désactivation complète de l'enregistrement (Live View uniquement).

RecordingModeEnum définit les stratégies d'enregistrement disponibles :

Mode Valeur d'énumération Description
Désactivé Disabled L'enregistrement est complètement désactivé. Utilisé principalement par les anciens appareils.
CVR (enregistrement vidéo en continu) Cvr La vidéo est enregistrée 24h/24, 7j/7. Nécessite un abonnement (par exemple, Google Home Premium.
EBR (enregistrement en cas d'événement) Ebr L'enregistrement est déclenché par des événements (personne, mouvement). La durée de la vidéo dépend de la durée de l'événement et de l'abonnement.
ETR (enregistrement déclenché par un événement) Etr Enregistrement d'un court aperçu (par exemple, 10 secondes) déclenché par des événements.
Live View LiveView L'enregistrement est désactivé, mais les utilisateurs peuvent toujours accéder à la diffusion en direct.
Images fixes Images Des photos instantanées sont enregistrées à la place de vidéos lorsque des événements se produisent.

Vérifier les modes d'enregistrement

Pour afficher la configuration d'enregistrement actuelle, vérifiez les attributs du trait 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,
      )
    )
  }
}

Modifier le mode d'enregistrement

Avant de procéder à la mise à jour, assurez-vous que l'index choisi dans l'attribut supportedRecordingModes est présent dans l'attribut availableRecordingModes.

Pour mettre à jour le mode sélectionné, utilisez la fonction setSelectedRecordingMode en transmettant l'index du mode choisi :

let recordingModeTrait: Google.RecordingModeTrait
let recordingModeID: UInt8

_ = try await recordingModeTrait.update {
  $0.setSelectedRecordingMode(recordingModeID)
}

Autres paramètres

Divers autres paramètres peuvent être contrôlés via les API Home.

Activer ou désactiver la vision nocturne

Pour activer ou désactiver la vision nocturne de la caméra, utilisez TriStateAutoEnum pour mettre à jour l'attribut nightVision du trait CameraAvStreamManagementTrait à l'aide de la fonction setNightVision intégrée :

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

Modifier la luminosité du voyant d'état LED

Pour modifier la luminosité du voyant d'état, utilisez ThreeLevelAutoEnum pour mettre à jour l'attribut statusLightBrightness du trait CameraAvStreamManagementTrait à l'aide de la fonction setStatusLightBrightness intégrée :

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

Modifier le champ de vision de la caméra

Le champ de vision de la caméra est identique à la fonctionnalité "Zoomer et recadrer" décrite dans l'article d'aide Zoomer et améliorer l'affichage vidéo de la caméra Nest.

Le champ de vision est défini dans un ViewportStruct qui contient quatre valeurs utilisées comme coordonnées du champ de vision. Les coordonnées sont définies comme suit :

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

La détermination des valeurs pour ViewportStruct dépend de l'UI et de l'implémentation de la caméra d'une application. Pour définir le champ de vision de la vidéo de la caméra, mettez à jour l'attribut viewport du trait CameraAvStreamManagementTrait avec un ViewportStruct à l'aide de la fonction setViewport intégrée.

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

}

Générer un TransportOptionsStruct

Certains paramètres nécessitent de modifier les propriétés d'un TransportOptionsStruct, qui est ensuite transmis aux options de transport d'une connexion de flux en continu. Pour Swift, cette structure doit être générée avant la mise à jour des propriétés.

Utilisez cette fonction d'assistance pour générer la structure à utiliser avec les modifications de paramètres suivantes :

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
}

Activer ou désactiver les analyses

Chaque appareil peut choisir individuellement d'envoyer des données d'analyse détaillées au cloud Google Home (voir Cloud Monitoring pour les API Home).

Pour activer l'analyse pour un appareil, définissez la propriété analyticsEnabled) de ExtendedGeneralDiagnosticsTrait sur true. Lorsque vous définissez analyticsEnabled, une autre propriété, logUploadEnabled, est automatiquement définie sur true, ce qui permet d'importer les fichiers journaux d'analyse dans le cloud Google Home.

// Enable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(true)
}

// Disable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(false)
}

Configurations de transport et d'enregistrement

Cette section traite des paramètres liés à la qualité du flux de la caméra et au déclenchement d'événements. Ces paramètres sont gérés par la caractéristique PushAvStreamTransport.

Lire les paramètres de transport

Cette section explique comment récupérer la configuration actuelle d'une caméra ou d'une sonnette. Il récupère la caractéristique PushAvStreamTransport, recherche la connexion spécifique utilisée pour l'enregistrement, puis extrait les valeurs actuelles de la qualité de la bande passante, de la sensibilité d'activation et de la durée maximale de l'événement.

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

Mettre à jour les paramètres de transport

Cette section explique comment modifier les paramètres de transport. Il crée un TransportOptionsStruct contenant les nouvelles valeurs, puis utilise la commande modifyPushTransport pour renvoyer ces paramètres mis à jour à l'appareil, en les appliquant à la connexion d'enregistrement trouvée à l'étape précédente.

Pour modifier ces paramètres, utilisez la commande modifyPushTransport avec un 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
)

Déterminer la qualité de la bande passante

La propriété videoStreamId de TransportOptionsStruct correspond à une configuration de flux vidéo spécifique.

Pour obtenir les flux vidéo compatibles, reportez-vous à l'attribut allocatedVideoStreams, qui est une liste de VideoStreamStructs. à partir de la caractéristique CameraAvStreamManagement de l'appareil.

Ajuster la sensibilité d'activation de l'appareil

La propriété motionSensitivity de TransportTriggerOptionsStruct correspond aux valeurs suivantes :

Libellé Valeur (UInt8)
Faible 1
Moyenne 5
Élevée 10

Ajuster la durée maximale des événements

La propriété maxDuration de TransportMotionTriggerTimeControlStruct correspond aux durées UInt32 suivantes (en secondes) :

  • 10, 15, 30, 60, 120, 180

Paramètres du carillon

Vous pouvez contrôler différents paramètres du carillon de la sonnette via les API Home.

Modifier le son du carillon

Pour modifier le son du carillon de la sonnette, commencez par obtenir la liste des sons de carillon installés sur l'appareil à l'aide de l'attribut installedChimeSounds du trait ChimeTrait :

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

Ensuite, mettez à jour l'attribut selectedChime du trait ChimeTrait à l'aide de la fonction setSelectedChime intégrée :

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

Utiliser un carillon externe

   Implémenté dans l'application exemple pour iOS   

La sonnette peut être configurée pour utiliser un carillon externe, comme une sonnette mécanique installée à l'intérieur de la maison. Ce paramètre doit être configuré lors de l'installation de la sonnette pour éviter d'endommager le carillon externe.

Pour indiquer le type de carillon externe installé, utilisez ExternalChimeType pour mettre à jour l'attribut externalChime du trait ChimeTrait à l'aide de la fonction setExternalChime intégrée :

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

Modifier la durée du carillon externe

La durée, en secondes, pendant laquelle un carillon externe sonne peut être configurée via les API Home. Si le carillon externe est compatible avec une durée de carillon, l'utilisateur peut vouloir la configurer.

La valeur définie ici dépend des spécifications du carillon externe lui-même et de la durée de sonnerie recommandée.

Pour modifier la durée du carillon externe, mettez à jour l'attribut externalChimeDurationSeconds du trait ChimeTrait à l'aide de la fonction setExternalChimeDurationSeconds intégrée :

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

Activer un thème de carillon

   Implémenté dans l'application exemple pour iOS   

Certaines sonnettes peuvent proposer des carillons qui ne sont disponibles que pendant une durée limitée. Par exemple, des carillons spécifiques pour les fêtes. On appelle cela des thèmes de carillon.

Pour voir quels thèmes de carillon sont disponibles pour un utilisateur, créez un filtre de plage horaire et utilisez-le pour filtrer les résultats de la commande getAvailableThemes du trait ChimeThemes. Cette commande renvoie une liste des thèmes disponibles, y compris leurs noms.

L'exemple suivant montre comment filtrer la liste. Un thème est considéré comme actif si l'heure actuelle se situe entre ses heures de début et de fin (les valeurs startTimeSeconds et endTimeSeconds, respectivement). Si aucune heure de début n'est définie, la règle est considérée comme active depuis le début. Si aucune heure de fin n'est définie, elle reste active indéfiniment. Si les deux sont manquants, le thème est toujours actif.

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

Une fois que vous avez le nom du thème souhaité, par exemple Christmas, vous pouvez le sélectionner à l'aide de la fonction setSelectedTimeboxedThemeName() sur la caractéristique ChimeThemes ChimeThemes.

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

Paramètres des annonces de visiteurs

Vous pouvez interroger et gérer les paramètres d'annonce de visiteurs pour les sonnettes à l'aide du trait VisitorAnnouncement des API Home. Ce trait détermine si la présence d'un visiteur est annoncée sur les enceintes intelligentes ou les écrans connectés Google lorsque quelqu'un sonne à la porte.

L'exemple suivant montre comment vérifier si les annonces de visiteurs sont activées et comment modifier ce paramètre :

let visitorAnnouncementsEnabled: Bool = visitorAnnouncementTrait.attributes.visitorAnnouncementsEnabled

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

Mettre un appareil hors service

Pour supprimer une sonnette d'une structure, appelez device.decommission(). La mise hors service invite l'utilisateur à confirmer l'opération sur un écran géré par Google, l'avertissant que l'historique vidéo en continu, l'historique des événements, les extraits et les données de la bibliothèque de visages familiers enregistrés seront définitivement supprimés de la structure.

Pour obtenir des instructions détaillées et des exemples de code, consultez Supprimer un appareil.