מדריך למכשיר התרמוסטט

אפשר להטמיע את סוג המכשיר Thermostat באמצעות כמה מאפיינים של Home API, אבל המאפיין הראשי הוא Thermostat. בהמשך מפורטים המאפיינים הנדרשים והאופציונליים של מכשירי Thermostat.

סוג המכשיר של Home APIs מאפיינים אפליקציה לדוגמה תרחיש לדוגמה

תרמוסטט

ThermostatDevice

מכשיר שיכול להכיל חיישנים מובנים או נפרדים לטמפרטורה, לחות או נוכחות, ומאפשר להגדיר את הטמפרטורה הרצויה. תרמוסטט יכול לשלוח התראות לגבי דרישות החימום או הקירור ליחידת חימום או קירור (לדוגמה, מאייד אוויר פנימי), או לכלול מנגנון לשלוט ישירות ביחידת חימום או קירור.

מאפיינים נדרשים
     matter Identify
     matter Thermostat

מאפיינים אופציונליים
     matter הגדרת ממשק המשתמש של התרמוסטט
     google תרמוסטט מורחב
תרמוסטט

תמיכה ב-Automation API

ב-Automation API יש תמיכה במאפיינים וברכיבים הבאים של התרמוסטט.

מאפיין סוג המאפיין סוג הרכיב רכיב
תרמוסטט matter פקודה SetpointRaiseLower
תרמוסטט matter מאפיין activePresetHandle
תרמוסטט matter מאפיין localTemperature
תרמוסטט matter מאפיין נוכחות
תרמוסטט matter מאפיין occupiedCoolingSetpoint
תרמוסטט matter מאפיין occupiedHeatingSetpoint
תרמוסטט matter מאפיין outdoorTemperature
תרמוסטט matter מאפיין setpointChangeSource
תרמוסטט matter מאפיין systemMode
תרמוסטט matter מאפיין temperatureSetpointHold
תרמוסטט matter מאפיין temperatureSetpointHoldDuration
תרמוסטט matter מאפיין thermostatRunningMode
תרמוסטט matter מאפיין thermostatRunningState
תרמוסטט matter מאפיין unoccupiedCoolingSetpoint
תרמוסטט matter מאפיין unoccupiedHeatingSetpoint
ExtendedThermostat google מאפיין activePresetHandle
ExtendedThermostat google מאפיין activeRemoteTemperatureSensorIds
ExtendedThermostat google מאפיין averageLocalTemperature
ExtendedThermostat google מאפיין extendedRunningMode
ExtendedThermostat google מאפיין extendedSystemMode
SimplifiedThermostat google פקודה SetSystemMode
SimplifiedThermostat google מאפיין systemMode

אחזור טמפרטורת הסביבה

אחזור טמפרטורת הסביבה באמצעות התרמוסטט

כדי לקבל את הטמפרטורה הסביבתית של התרמוסטט באמצעות המאפיין Thermostat, קוראים את המאפיין localTemperature.

Device API

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

Automation API

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

אחזור טמפרטורת הסביבה באמצעות TemperatureMeasurement

כדי לקבל את הטמפרטורה הסביבתית של התרמוסטט באמצעות המאפיין TemperatureMeasurement, קוראים את המאפיין measuredValue.

Device API

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

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

Automation API

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

אחזור הטמפרטורה הממוצעת באמצעות ExtendedThermostat

כדי לקבל את הטמפרטורה הממוצעת של כמה חיישנים, קוראים את המאפיין averageLocalTemperature של המאפיין ExtendedThermostat.

Device API

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

Automation API

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

אחזור של הלחות בסביבה

כדי לקבל את הלחות הסביבתית של התרמוסטט באמצעות המאפיין RelativeHumidityMeasurement, קוראים את המאפיין measuredValue.

Device API

// Get the ambient humidity

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

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

Automation API

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

בחירת סולם הטמפרטורה המוצג

כדי לשנות את יחידת המדידה של הטמפרטורה שמוצגת במסך התרמוסטט, מגדירים את המאפיין temperatureDisplayMode של ThermostatUserInterfaceConfigurationTrait לערך TemperatureDisplayModeEnum.Celsius או לערך TemperatureDisplayModeEnum.Fahrenheit.

Device API

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

Automation API

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

שינוי מצב ההפעלה

אפשר להגביל את התרמוסטט למצבי הפעלה מסוימים, שמוגדרים על ידי ThermostatTrait.SystemModeEnum, על ידי הגדרת המאפיין ThermostatTrait.Attributes.systemMode, שהערכים שלו מוגדרים על ידי ThermostatTrait.Attributes.SystemModeEnum.

Device API

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

Automation API

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

כשהתרמוסטט מוגדר ל-SystemModeEnum.Auto, אפשר לקרוא מידע נוסף על מצב ההפעלה של התרמוסטט מהשדה ThermostatTrait.Attributes.thermostatRunningMode, שמאוכלס בערכים מהשדה ThermostatRunningModeEnum.

Device API

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

Automation API

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 נועד לייעל את תהליך הגדרת מצב ההפעלה באוטומציות. כדי לשנות את מצב הפעולה של התרמוסטט באמצעות SimplifiedThermostatTrait, משתמשים ב-SetSystemModeCommand, שהערכים שלו מוגדרים על ידי SimplifiedThermostatTrait.SystemModeEnum.

המאפיין הזה זמין לשימוש רק עם Automation API.

Automation API

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

כדי לקבוע את מצבי המערכת שבהם התרמוסטט יכול לפעול, קוראים את הערכים של ThermostatTrait.Attributes.controlSequenceOfOperation, שמוגדרים על ידי ThermostatTrait.ControlSequenceOfOperationEnum.

Device API

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

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

Automation API

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

שינוי מצב הפעולה של התכנות

אפשר לשנות את מצב הפעולה המתוזמן של התרמוסטט באמצעות thermostatProgrammingOperationMode של Thermostat, שהערכים שלו מוגדרים על ידי ProgrammingOperationModeBitmap.

Device API

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

Automation API

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

שינוי הטמפרטורה לשמירה

כדי לשנות את נקודת היעד של הטמפרטורה באמצעות Thermostat, צריך להפעיל את הפונקציה ThermostatTrait.SetpointRaiseLowerCommand.

Device API

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)

Automation API

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

מתן עדיפות לטמפרטורה לשמירה

כדי שהנקודת היעד של הטמפרטורה תהיה בעדיפות גבוהה יותר מלוח זמנים מתוכנת מראש, מגדירים את המאפיין temperatureSetpointHold של ThermostatTrait לערך TemperatureSetpointHoldEnum.SetpointHoldOn. כדי שהלוח הזמנים יהיה בעדיפות גבוהה יותר, מגדירים אותו לערך TemperatureSetpointHoldEnum.SetpointHoldOff.

Device API

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

Automation API

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

מגדירים את ThermostatTrait.Attributes.temperatureSetpointHoldDuration כדי לקבוע כמה דקות ההחזקה בנקודת היעד תהיה פעילה.

Device API

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

Automation API

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

כדי לשנות את מדיניות ההחזקה של נקודת היעד של הטמפרטורה, שמגדירה איך ומתי מצב ההחזקה של התרמוסטט מסתיים, צריך להפעיל את הפונקציה ThermostatTrait.SetTemperatureSetpointHoldPolicyCommand.

הערכים החוקיים נקבעים על ידי TemperatureSetpointHoldPolicyBitmap.

Device API

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