Guida al dispositivo termostato

Il tipo di dispositivo termostato può essere implementato utilizzando diversi tratti dell'API Home, ma il tratto principale è Thermostat. Di seguito sono riportati i tratti obbligatori e facoltativi per i dispositivi termostato.

Tipo di dispositivo per le API Home Tratti App di esempio Caso d'uso

Termostato

ThermostatDevice

Un dispositivo in grado di avere sensori integrati o separati per temperatura, umidità o presenza e che consente di impostare la temperatura desiderata. Un termostato è in grado di inviare notifiche relative ai requisiti di riscaldamento e/o raffreddamento a un'unità di riscaldamento/raffreddamento (ad esempio una unità di trattamento dell'aria interna) o è in grado di includere un meccanismo per controllare direttamente un'unità di riscaldamento o raffreddamento.

Attributi obbligatori
     matter Identify
     matter Thermostat

Attributi facoltativi
     matter Configurazione dell'interfaccia utente del termostato
     google Termostato avanzato
Termostato

Supporto dell'API Automation

Nell'API Automation sono supportati i seguenti elementi e tratti di Thermostat.

Tratto Tipo di tratto Tipo di elemento Elemento
Termostato matter Comando SetpointRaiseLower
Termostato matter Attributo activePresetHandle
Termostato matter Attributo localTemperature
Termostato matter Attributo numero di persone
Termostato matter Attributo occupiedCoolingSetpoint
Termostato matter Attributo occupiedHeatingSetpoint
Termostato matter Attributo outdoorTemperature
Termostato matter Attributo setpointChangeSource
Termostato matter Attributo systemMode
Termostato matter Attributo temperatureSetpointHold
Termostato matter Attributo temperatureSetpointHoldDuration
Termostato matter Attributo thermostatRunningMode
Termostato matter Attributo thermostatRunningState
Termostato matter Attributo unoccupiedCoolingSetpoint
Termostato matter Attributo unoccupiedHeatingSetpoint
ExtendedThermostat google Attributo activePresetHandle
ExtendedThermostat google Attributo activeRemoteTemperatureSensorIds
ExtendedThermostat google Attributo averageLocalTemperature
ExtendedThermostat google Attributo extendedRunningMode
ExtendedThermostat google Attributo extendedSystemMode
SimplifiedThermostat google Comando SetSystemMode
SimplifiedThermostat google Attributo systemMode

Ottenere la temperatura ambiente

Ottenere la temperatura ambiente utilizzando il termostato

Per ottenere la temperatura ambiente del termostato utilizzando il tratto Thermostat, leggi l'attributo localTemperature.

API Device

// Get the ambient temperature
val thermostat = home.devices().list().first { device -> device.has(Thermostat) }

val thermostatTraitFlow: Flow<Thermostat?> =
  thermostat
    .type(ThermostatDevice)
    .mapNotNull { it.standardTraits.thermostat }
    .distinctUntilChanged()

val localTempFlow = thermostatTraitFlow.mapNotNull { it?.localTemperature }

API Automation

val automation = automation {
  sequential {
    val starterNode = starter<_>(thermostat, ThermostatDevice, Thermostat)

    // If the temperature is higher than 35C...
    condition { expression = starterNode.localTemperature greaterThan 35 }

    // ...and the automation hasn't been run for at least an hour...
    suppressFor(Duration.ofHours(1))

    // ...broadcast a message
    action(speaker, SpeakerDevice) {
      command(AssistantBroadcast.broadcast("It's very hot outside."))
    }
  }
}

Ottenere la temperatura ambiente utilizzando TemperatureMeasurement

Per ottenere la temperatura ambiente del termostato utilizzando il tratto TemperatureMeasurement, leggi l'attributo measuredValue.

API Device

val temperatureTraitFlow: Flow<TemperatureMeasurement?> =
  thermostat
    .type(TemperatureSensorDevice)
    .map { it.standardTraits.temperatureMeasurement }
    .distinctUntilChanged()

val localTemp: Short? = temperatureTraitFlow.first()?.measuredValue

API Automation

val automation = automation {
  sequential {
    val temperature = starter<_>(thermostat, ThermostatDevice, TemperatureMeasurement)
    val stateReaderNode = stateReader<_>(light, DimmableLightDevice, OnOff)
    condition() {
      val expr1 = temperature.measuredValue greaterThanOrEquals 35
      val expr2 = stateReaderNode.onOff equals true
      expression = expr1 and expr2
    }
    action(light, DimmableLightDevice) { command(OnOff.on()) }
  }
}

Ottenere la temperatura media utilizzando ExtendedThermostat

Per ottenere la temperatura media di più sensori, leggi l'attributo averageLocalTemperature della caratteristica ExtendedThermostat.

API Device

// Get the average temperature
val thermostat = home.devices().list().first { device -> device.has(TemperatureSensorDevice) }

val temperatureTraitFlow: Flow<TemperatureMeasurement?> =
  thermostat
    .type(TemperatureSensorDevice)
    .map { it.standardTraits.temperatureMeasurement }
    .distinctUntilChanged()

val localTemp: Short? = temperatureTraitFlow.first()?.measuredValue

API Automation

val automation = automation {
  sequential {
    val temperature = starter<_>(thermostat, ThermostatDevice, ExtendedThermostat)
    val stateReaderNode = stateReader<_>(light, DimmableLightDevice, OnOff)
    //  if the average temperature is >= 35C
    condition() {
      val expr1 = temperature.averageLocalTemperature greaterThanOrEquals 35
      val expr2 = stateReaderNode.onOff equals true
      expression = expr1 and expr2
    }
    // Turn on the light
    action(light, DimmableLightDevice) { command(OnOff.on()) }
  }
}

Ottenere l'umidità ambientale

Per ottenere l'umidità ambientale del termostato utilizzando la caratteristica RelativeHumidityMeasurement, leggi l'attributo measuredValue.

API Device

// Get the ambient humidity

val humidityTraitFlow: Flow<RelativeHumidityMeasurement?> =
  humiditySensingThermostat
    .type(HumiditySensorDevice)
    .map { it.standardTraits.relativeHumidityMeasurement }
    .distinctUntilChanged()

val localHumidity: UShort? = humidityTraitFlow.first()?.measuredValue

API Automation

val automation = automation {
  sequential {
    val humidity = starter<_>(thermostat, HumiditySensorDevice, RelativeHumidityMeasurement)
    val stateReaderNode = stateReader<_>(light, DimmableLightDevice, OnOff)
    // if the ambient humidity is >= 80%
    condition() {
      val expr1 = (humidity.measuredValue greaterThanOrEquals 80u)
      val expr2 = (stateReaderNode.onOff equals true)
      expression = expr1 and expr2
    }
    // Turn on the light
    action(light, DimmableLightDevice) { command(OnOff.on()) }
  }
}

Selezionare la scala di temperatura visualizzata

Per modificare l'unità di misura della temperatura utilizzata per il display del termostato, imposta l'attributo temperatureDisplayMode di ThermostatUserInterfaceConfigurationTrait su TemperatureDisplayModeEnum.Celsius o TemperatureDisplayModeEnum.Fahrenheit.

API Device

// Set the displayed temperature scale to Fahrenheit
val uiConfig =
  home
    .devices()
    .list()
    .filter { device -> device.has(ThermostatUserInterfaceConfiguration) }
    .first()

val uiConfigTraitFlow: Flow<ThermostatUserInterfaceConfiguration?> =
  uiConfig
    .type(ThermostatDevice)
    .map { it.standardTraits.thermostatUserInterfaceConfiguration }
    .distinctUntilChanged()

val uiConfigTrait: ThermostatUserInterfaceConfiguration = uiConfigTraitFlow.first()!!

if (
  uiConfigTrait.supports(ThermostatUserInterfaceConfiguration.Attribute.temperatureDisplayMode)
) {
  val unused =
    uiConfigTrait.update { setTemperatureDisplayMode(TemperatureDisplayModeEnum.Fahrenheit) }
}

API Automation

val automation = automation {
  isActive = true
  sequential {
    val stateReaderNode =
      stateReader<_>(thermostat, ThermostatDevice, ThermostatUserInterfaceConfiguration)

    // When someone says "Show the temperature in Fahrenheit",
    val unused =
      starter<_>(structure, VoiceStarter.OkGoogleEvent) {
        parameter(VoiceStarter.OkGoogleEvent.query("Show the temperature in Fahrenheit"))
      }
    // if the temperature isn't being shown in Fahrenheit
    condition() {
      expression =
        stateReaderNode.temperatureDisplayMode notEquals TemperatureDisplayModeEnum.Fahrenheit
    }
    // display the current temperature using Fahrenheit
    action(thermostat, ThermostatDevice) {
      update(ThermostatUserInterfaceConfiguration) {
        setTemperatureDisplayMode(TemperatureDisplayModeEnum.Fahrenheit)
      }
    }
  }
}

Modificare la modalità di funzionamento

Il termostato può essere limitato a determinate modalità di funzionamento, definite da ThermostatTrait.SystemModeEnum, impostando l'attributo ThermostatTrait.Attributes.systemMode, cuyos valores están definidos por ThermostatTrait.Attributes.SystemModeEnum.

API Device

val thermostatDevice = structure.devices().list().first { device -> device.has(Thermostat) }

val thermostatTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val thermostatTrait: Thermostat = thermostatTraitFlow.first()!!

// Set the system mode to Auto
if (thermostatTrait.supports(Thermostat.Attribute.systemMode)) {
  val unused = thermostatTrait.update { setSystemMode(SystemModeEnum.Auto) }
}

API Automation

val automation = automation {
  isActive = true
  // When the door lock state changes
  sequential {
    val doorLockEvent = starter<_>(doorLock, DoorLockDevice, LockOperationEvent)
    val stateReaderNode = stateReader<_>(thermostat, ThermostatDevice, SimplifiedThermostat)

    // if the door is unlocked and the thermostat is in Eco mode
    condition() {
      val expr1 = (doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock)
      val expr2 = (stateReaderNode.systemMode equals SimplifiedThermostatSystemModeEnum.Eco)
      expression = expr1 and expr2
    }

    // Set the thermostat to Auto mode
    action(thermostat, ThermostatDevice) {
      command(SimplifiedThermostat.setSystemMode(SimplifiedThermostatSystemModeEnum.Auto))
    }
  }
}

Quando il termostato è impostato su SystemModeEnum.Auto, è possibile leggere ulteriori informazioni sulla modalità di funzionamento del termostato da ThermostatTrait.Attributes.thermostatRunningMode che viene compilato con i valori di ThermostatRunningModeEnum.

API Device

// Get the current thermostat running mode

val runningModeTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val runningMode: ThermostatTrait.ThermostatRunningModeEnum? =
  runningModeTraitFlow.first()?.thermostatRunningMode

API Automation

val automation = automation {
  isActive = true
  sequential {
    val stateReaderNode = stateReader<_>(thermostat, ThermostatDevice, Thermostat)
    // at 10:00am
    val unused =
      starter<_>(structure, Time.ScheduledTimeEvent) {
        parameter(Time.ScheduledTimeEvent.clockTime(LocalTime.of(10, 0, 0, 0)))
      }

    // if the thermostat is in Auto mode and is currently cooling
    condition() {
      val expr1 = (stateReaderNode.systemMode equals ThermostatTrait.SystemModeEnum.Auto)
      val expr2 =
        (stateReaderNode.thermostatRunningMode equals
          ThermostatTrait.ThermostatRunningModeEnum.Cool)
      expression = expr1 and expr2
    }
    // announce that it's in Cool mode
    action(structure) {
      command(AssistantBroadcast.broadcast("The thermostat is currently running in Cool mode."))
    }
  }
}

SimplifiedThermostatTrait è progettato per semplificare il processo di impostazione della modalità di funzionamento nelle automazioni. Per cambiare la modalità di funzionamento del termostato utilizzando il pulsante SimplifiedThermostatTrait, usa SetSystemModeCommand, i cui valori sono definiti da SimplifiedThermostatTrait.SystemModeEnum.

Questo trait è disponibile solo per l'utilizzo con l'API Automation.

API Automation

val automation = automation {
  isActive = true

  sequential {
    // When the presence state changes...
    val starterNode = starter<_>(structure, AreaPresenceState)
    // ...and if the area is unoccupied...
    condition() {
      expression = starterNode.presenceState equals PresenceState.PresenceStateVacant
    }
    // Set the thermostat to Eco mode
    action(thermostat, ThermostatDevice) {
      command(SimplifiedThermostat.setSystemMode(SimplifiedThermostatSystemModeEnum.Eco))
    }
  }
}

Per determinare le modalità di sistema in cui può funzionare un termostato, leggi il messaggio ThermostatTrait.Attributes.controlSequenceOfOperation, i cui valori sono determinati da ThermostatTrait.ControlSequenceOfOperationEnum.

API Device

// Get the controlSequenceOfOperation
val standardTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val controlSequenceOfOperation: ThermostatTrait.ControlSequenceOfOperationEnum? =
  standardTraitFlow.first()?.controlSequenceOfOperation

API Automation

val automation = automation {
  isActive = true
  sequential {
    val stateReaderNode = stateReader<_>(thermostat, ThermostatDevice, Thermostat)
    // When someone says "Switch to cool mode",
    val unused =
      starter<_>(structure, VoiceStarter.OkGoogleEvent) {
        parameter(VoiceStarter.OkGoogleEvent.query("Switch to cool mode"))
      }
    // if the thermostat is capable of operating in Cool mode,
    condition() {
      val expr1 =
        stateReaderNode.controlSequenceOfOperation notEquals
          ControlSequenceOfOperationEnum.HeatingOnly
      val expr2 =
        stateReaderNode.controlSequenceOfOperation notEquals
          ControlSequenceOfOperationEnum.HeatingWithReheat
      expression = expr1 and expr2
    }

    action(thermostat, ThermostatDevice) {
      // switch to Cool mode
      update(SimplifiedThermostat) {
        command(SimplifiedThermostat.setSystemMode(SimplifiedThermostatSystemModeEnum.Cool))
      }
    }
  }
}

Modificare la modalità di funzionamento della programmazione

La modalità di funzionamento della programmazione del termostato può essere modificata utilizzando il valore thermostatProgrammingOperationMode del messaggio Thermostat, i cui valori sono definiti dal messaggio ProgrammingOperationModeBitmap.

API Device

val thermostatTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val thermostatTrait: Thermostat = thermostatTraitFlow.first()!!

if (thermostatTrait.supports(Thermostat.Attribute.thermostatProgrammingOperationMode)) {
  val programmingOperationMode = thermostatTrait.thermostatProgrammingOperationMode!!

  // Enable autoRecovery on the thermostatProgrammingOperationMode
  val unused =
    thermostatTrait.update {
      setThermostatProgrammingOperationMode(
        ThermostatTrait.ProgrammingOperationModeBitmap(
          programmingOperationMode.scheduleActive,
          true,
          programmingOperationMode.economy,
        )
      )
    }
}

API Automation

// When someone says "Reset programming operation mode"
val automation = automation {
  isActive = true
  sequential {
    val unused =
      starter<_>(structure, VoiceStarter.OkGoogleEvent) {
        parameter(VoiceStarter.OkGoogleEvent.query("Reset programming operation mode"))
      }
    // Set all the flags on the programming operation mode
    action(thermostat, ThermostatDevice) {
      update(Thermostat) {
        setThermostatProgrammingOperationMode(ProgrammingOperationModeBitmap(true, true, true))
      }
    }
  }
}

Modificare il set-point della temperatura

Per modificare il set-point della temperatura utilizzando il pulsante Thermostat, chiama ThermostatTrait.SetpointRaiseLowerCommand.

API Device

val thermostatTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val thermostatTrait: Thermostat = thermostatTraitFlow.first()!!

// lower the temperature setpoint by 1 degree C
thermostatTrait.setpointRaiseLower(amount = 1, mode = SetpointRaiseLowerModeEnum.Cool)

API Automation

val automation = automation {
  isActive = true
  sequential {
    val stateReaderNode = stateReader<_>(thermostat, ThermostatDevice, Thermostat)
    // At 10:00pm
    val unused =
      starter<_>(structure, Time.ScheduledTimeEvent) {
        parameter(Time.ScheduledTimeEvent.clockTime(LocalTime.of(22, 0, 0, 0)))
      }
    // if the setpoint is warmer than 19C
    condition() { expression = stateReaderNode.occupiedCoolingSetpoint greaterThan 19 }

    // lower the temperature setpoint by 5 degrees
    action(thermostat, ThermostatDevice) {
      command(Thermostat.setpointRaiseLower(SetpointRaiseLowerModeEnum.Cool, 5))
    }
  }
}

Dare la priorità a un set-point di temperatura

Puoi fare in modo che un setpoint di temperatura abbia la precedenza su una programmazione preimpostata impostando l'attributo temperatureSetpointHold di ThermostatTrait su TemperatureSetpointHoldEnum.SetpointHoldOn oppure puoi fare in modo che la programmazione abbia la precedenza impostandola su TemperatureSetpointHoldEnum.SetpointHoldOff.

API Device

val thermostatTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val thermostatTrait: Thermostat = thermostatTraitFlow.first()!!

if (thermostatTrait.supports(Thermostat.Attribute.temperatureSetpointHold)) {
  // Set temperatureSetpointHold to SetpointHoldOn
  // allowing temperature setpoints to override any preprogrammed schedules.

  val unused =
    thermostatTrait.update {
      setTemperatureSetpointHold(TemperatureSetpointHoldEnum.SetpointHoldOn)
    }

API Automation

val automation = automation {
  isActive = true
  sequential {

    // When someone says "Prioritize thermostat setpoint"
    val unused =
      starter<_>(structure, VoiceStarter.OkGoogleEvent) {
        parameter(VoiceStarter.OkGoogleEvent.query("Prioritize thermostat setpoint"))
      }
    // make temperature setpoints override any preprogrammed schedules.
    action(thermostat, ThermostatDevice) {
      val unused2 =
        update(Thermostat) {
          setTemperatureSetpointHold(TemperatureSetpointHoldEnum.SetpointHoldOn)
        }
    }
  }

Imposta ThermostatTrait.Attributes.temperatureSetpointHoldDuration per controllare per quanti minuti è attiva la mantenimento del setpoint.

API Device

val thermostatTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val thermostatTrait: Thermostat = thermostatTraitFlow.first()!!

if (thermostatTrait.supports(Thermostat.Attribute.temperatureSetpointHoldDuration)) {
  // Set the setpoint hold duration to 60 minutes
  val unused = thermostatTrait.update { setTemperatureSetpointHoldDuration(60u) }
}

API Automation

val automation = automation {
  isActive = true
  sequential {
    val stateReaderNode = stateReader<_>(thermostat, ThermostatDevice, Thermostat)
    val unused = starter<_>(thermostat, ThermostatDevice, Thermostat)

    // if the temperature setpoint hold duration is less than 60 minutes...
    condition() { expression = stateReaderNode.temperatureSetpointHoldDuration.lessThan(60u) }

    // ...and the automation hasn't been run for at least 24 hours...
    suppressFor(Duration.ofHours(24))

    // ...set the temperature setpoint hold duration to 60 minutes
    action(thermostat, ThermostatDevice) {
      val unused2 = update(Thermostat) { setTemperatureSetpointHoldDuration(60u) }
    }
  }
}

Per modificare il criterio di blocco del setpoint della temperatura, che determina come e quando termina lo stato di blocco del termostato, chiama ThermostatTrait.SetTemperatureSetpointHoldPolicyCommand.

I valori validi sono determinati da TemperatureSetpointHoldPolicyBitmap.

API Device

val thermostatTraitFlow: Flow<Thermostat?> =
  thermostat.type(ThermostatDevice).map { it.standardTraits.thermostat }.distinctUntilChanged()

val thermostatTrait: Thermostat = thermostatTraitFlow.first()!!
if (thermostatTrait.supports(Thermostat.Attribute.temperatureSetpointHoldPolicy)) {

  // Set the temperature setpoint hold policy to holdDurationElapsedOrPresetChanged
  val unused =
    thermostatTrait.setTemperatureSetpointHoldPolicy(
      ThermostatTrait.TemperatureSetpointHoldPolicyBitmap(
        holdDurationElapsed = false,
        holdDurationElapsedOrPresetChanged = true,
      )
    )
}

val automation = automation {
  isActive = true
  sequential {

    // When someone says "Set my preferred hold duration",
    val unused =
      starter<_>(structure, VoiceStarter.OkGoogleEvent) {
        parameter(VoiceStarter.OkGoogleEvent.query("Set my preferred hold duration"))
      }

    // set the temperature setpoint hold policy to holdDurationElapsedOrPresetChanged
    action(thermostat, ThermostatDevice) {
      command(
        Thermostat.setTemperatureSetpointHoldPolicy(
          TemperatureSetpointHoldPolicyBitmap(
            holdDurationElapsed = false,
            holdDurationElapsedOrPresetChanged = true,
          )
        )
      )
    }
  }
}