Light device guide

Light devices use standard Matter traits to identify fixtures, toggle power states, and adjust brightness levels.

The most basic light device type is the OnOffLight which is implemented with the OnOff and Identify traits and optionally supports the LevelControl trait and LightEffects trait.

Other light types offer additional capabilities and are implemented with different traits:

Home APIs Device Type Traits Kotlin Sample App Use Case

Color Temperature Light

ColorTemperatureLightDevice

home.matter.0000.types.010c

A lighting device that is capable of being switched on or off, the intensity of its light adjusted, and its color temperature adjusted.

Required Traits
     matter Identify
     matter OnOff
     matter LevelControl
     matter ColorControl

Optional Traits
     google LightEffects
     google ExtendedColorControl

on and off, brightness
Light

Dimmable Light

DimmableLightDevice

home.matter.0000.types.0101

A lighting device that is capable of being switched on or off, the intensity of its light adjusted, and being switched by means of a bound occupancy sensor.

Required Traits
     matter Identify
     matter OnOff
     matter LevelControl

Optional Traits
     google LightEffects

on and off, brightness
Light

Extended Color Light

ExtendedColorLightDevice

home.matter.0000.types.010d

A lighting device that is capable of being switched on or off, the intensity of its light adjusted, its color temperature adjusted, and being switched by means of a bound occupancy sensor.

Required Traits
     matter Identify
     matter OnOff
     matter LevelControl
     matter ColorControl

Optional Traits
     google LightEffects
     google ExtendedColorControl

on and off, brightness
Light

On/Off Light

OnOffLightDevice

home.matter.0000.types.0100

A lighting device that is capable of being switched on or off.

Required Traits
     matter Identify
     matter OnOff

Optional Traits
     matter LevelControl
     google LightEffects

on and off, brightness
Light

Always check for attribute and command support for a device prior to using any features or attempting to update attributes. See Control devices on Android for more information.

Prerequisites

Before working with lighting devices and lighting curves, make sure your app initializes the Home SDK and includes the required imports:

import com.google.home.HomeDevice
import com.google.home.Structure
import com.google.home.google.DayOfWeek
import com.google.home.google.ExtendedColorControl
import com.google.home.google.ExtendedColorControlTrait
import com.google.home.google.LightingCurve
import com.google.home.google.LightingCurveTrait
import com.google.home.matter.standard.ColorControl
import com.google.home.matter.standard.ColorControlTrait
import com.google.home.matter.standard.ColorTemperatureLightDevice
import com.google.home.matter.standard.DimmableLightDevice
import com.google.home.matter.standard.ExtendedColorLightDevice
import com.google.home.matter.standard.GeneralDiagnostics
import com.google.home.matter.standard.Identify
import com.google.home.matter.standard.IdentifyTrait
import com.google.home.matter.standard.LevelControl
import com.google.home.matter.standard.LevelControlTrait
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffLightDevice
import com.google.home.matter.standard.OnOffTrait
import com.google.home.matter.standard.RootNodeDevice
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull

Find light devices

To find lighting devices in a structure, filter the device list by device type, such as OnOffLightDevice and DimmableLightDevice .

// Get all On/Off Light devices in the structure
val onOffLights: List<HomeDevice> =
  home.devices().list().filter { it.has(OnOffLightDevice) }

// Get all Dimmable Light devices in the structure
val dimmableLights: List<HomeDevice> =
  home.devices().list().filter { it.has(DimmableLightDevice) }

// Retrieve a specific device type instance to access its traits
val onOffLightDevice: OnOffLightDevice? =
  onOffLights.firstOrNull()?.type(OnOffLightDevice)?.firstOrNull()

val dimmableLightDevice: DimmableLightDevice? =
  dimmableLights.firstOrNull()?.type(DimmableLightDevice)?.firstOrNull()

You can also retrieve all lighting devices across multiple light device types in a single filter:

// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

Get basic information about a device

   Implemented in Sample App for Android   

The BasicInformation trait includes information like vendor name, vendor ID, product ID, product name (includes model information), and software version for a device:

// Get device basic information. All general information traits are on the RootNodeDevice type.
    device.type(RootNodeDevice).first().standardTraits.basicInformation?.let { basicInformation ->
        println("vendorName ${basicInformation.vendorName}")
        println("vendorId ${basicInformation.vendorId}")
        println("productId ${basicInformation.productId}")
        println("productName ${basicInformation.productName}")
        println("softwareVersion ${basicInformation.softwareVersion}")
    }

Identify a lighting device

When a room contains multiple lights, you can help users locate a specific physical fixture by triggering a visual identification state, such as blinking the light for a few seconds. All four light device types require the Identify trait.

Call the identify command with an identifyTime duration in seconds to start the identification state. Passing 0 stops the identification state immediately. You can also call triggerEffect to run a specific visual effect, such as Blink or Breathe.

suspend fun identifyLight(lightDevice: DimmableLightDevice) {
  val identifyTrait = lightDevice.standardTraits.identify ?: return

  // Blink the light for 10 seconds so the user can locate it
  if (identifyTrait.supports(Identify.Command.Identify)) {
    identifyTrait.identify(identifyTime = 10u)
  }

  // Or trigger a specific visual identification effect
  if (identifyTrait.supports(Identify.Command.TriggerEffect)) {
    identifyTrait.triggerEffect(
      effectIdentifier = IdentifyTrait.EffectIdentifierEnum.Blink,
      effectVariant = IdentifyTrait.EffectVariantEnum.Default
    )
  }
}

Check the connectivity of a lighting device

Connectivity for a device is actually checked at the device type level because some devices support multiple device types. The state returned is a combination of the connectivity states for all traits on that device.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

A state of partiallyOnline may be observed in the case of mixed device types when there is no internet connectivity. Matter standard traits may still be online due to local routing, but cloud-based traits will be offline.

Get the IP address of the device

To find the IP address of the device, use the networkInterfaces attribute of the GeneralDiagnosticsTrait. The addresses are returned as Data objects, which you can format to standard IPv4 or IPv6 strings using the Network framework:

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
}

Control lighting devices

The OnOffLight and DimmableLight device types use standard Matter traits to identify fixtures, toggle power states, and adjust brightness levels.

Turn a light on or off

Use the OnOff trait to read the current power state of an OnOffLight or DimmableLight and to switch the light on or off.

Before reading the onOff attribute, verify that the device supports it. Some devices operate as command-only endpoints and don't report state.

// Check if the OnOff trait supports the onOff attribute.
if (onOffTrait.supports(OnOff.Attribute.onOff)) {
  println("onOffTrait supports onOff state")
} else {
  println("onOffTrait is for a command only device!")
}

When onOff is true, the light is on. When onOff is false, the light is off.

To change the power state of the light, verify that the trait supports the intended command and then call on(), off(), or toggle().

// Check if the OnOff trait supports the toggle command.
if (onOffTrait.supports(OnOff.Command.Toggle)) {
  println("onOffTrait supports toggle command")
} else {
  println("onOffTrait does not support stateful toggle command")
}
// Calling a command on a trait.
try {
  onOffTrait.toggle()
} catch (e: HomeException) {
  // Code for handling the exception
}

You can also call on() and off() directly to set an explicit state:

onOffTrait.off()
onOffTrait.on()

To turn off a light with a gradual visual transition, call offWithEffect() and specify an EffectIdentifierEnum value:

// Turn off the light using the DyingLight effect.
onOffTrait.offWithEffect(
  effectIdentifier = OnOffTrait.EffectIdentifierEnum.DyingLight,
  effectVariant = 0u,
)

Adjust brightness levels

A DimmableLight requires the LevelControl trait, and an OnOffLight can optionally support it. Use this trait to read and control the brightness level of a light.

The currentLevel attribute reports the current brightness level on a scale from 0 to 254. You can also inspect minLevel and maxLevel to determine the valid brightness range supported by the hardware.

To set the brightness to a specific value, call moveToLevel(). Note that moveToLevel() only changes the current level when the light is already on, unless you configure optionsOverride with executeIfOff. To automatically turn the light on when setting a non-zero brightness level (or turn it off when setting the level to minimum), use moveToLevelWithOnOff().

// Change the brightness of the light to 50%
levelControlTrait.moveToLevel(
  level = 127u.toUByte(),
  transitionTime = null,
  optionsMask = LevelControlTrait.OptionsBitmap(),
  optionsOverride = LevelControlTrait.OptionsBitmap(),
)

The following example reads the current brightness level and uses moveToLevelWithOnOff() to set a dimmable light to 75% brightness (190u) over a 1-second (10u tenths of a second) transition:

suspend fun setLightBrightness(lightDevice: DimmableLightDevice) {
  val levelControl = lightDevice.standardTraits.levelControl ?: return

  // Read the current brightness level (0 to 254)
  val currentLevel: UByte? = levelControl.currentLevel
  println("Current brightness level: $currentLevel")

  // Move to ~75% brightness (190 out of 254) and turn on the light if it is off
  if (levelControl.supports(LevelControl.Command.MoveToLevelWithOnOff)) {
    levelControl.moveToLevelWithOnOff(
      level = 190u,
      transitionTime = 10u,
      optionsMask = LevelControlTrait.OptionsBitmap(),
      optionsOverride = LevelControlTrait.OptionsBitmap()
    )
  }
}

You can also increment or decrement brightness relative to the current level by calling stepWithOnOff() with StepModeEnum.Up or StepModeEnum.Down and a stepSize.

Control color

The ColorControl trait is available on both the ColorTemperatureLightDevice and ExtendedColorLightDevice.

This trait lets you adjust color temperature in micro-reciprocal degrees or mireds.

val colorControlTrait =
  colorTempLightDevice.standardTraits.colorControl ?: return
// Read the current color temperature and hardware limits in mireds
// (Mireds = 1,000,000 / Kelvin; e.g., 370 mireds ≈ 2700K warm white, 250 mireds = 4000K cool white)
val currentMireds = colorControlTrait.colorTemperatureMireds
val minMireds = colorControlTrait.colorTempPhysicalMinMireds ?: 153u // ~6500K (coolest)
val maxMireds = colorControlTrait.colorTempPhysicalMaxMireds ?: 500u // 2000K (warmest)
// Clamp target (370 mireds ≈ 2700K) to the device's physical bounds
val targetMireds = 370u.toUShort().coerceIn(minMireds, maxMireds)
if (
  colorControlTrait.supports(
    ColorControl.Command.MoveToColorTemperature
  )
) {
  colorControlTrait.moveToColorTemperature(
    colorTemperatureMireds = targetMireds,
    transitionTime = 20u, // 2.0 seconds (in 0.1s units)
    optionsMask = ColorControlTrait.OptionsBitmap(),
    optionsOverride = ColorControlTrait.OptionsBitmap()
  )
}

You can also set color using CIE 1931 chromaticity coordinates and 16-bit hue and saturation values.

val colorControlTrait =
  extendedColorLightDevice.standardTraits.colorControl ?: return
// 1. Move to CIE 1931 xy chromaticity coordinates (scaled 0..65279)
// Example: x = 0.3127 (20493), y = 0.3290 (21561) for D65 white point
if (colorControlTrait.supports(ColorControl.Command.MoveToColor)) {
  colorControlTrait.moveToColor(
    colorX = 20493u,
    colorY = 21561u,
    transitionTime = 10u, // 1.0 second (in 0.1s units)
    optionsMask = ColorControlTrait.OptionsBitmap(),
    optionsOverride = ColorControlTrait.OptionsBitmap()
  )
}
val currentX = colorControlTrait.currentX
val currentY = colorControlTrait.currentY
// 2. Move to 16-bit Enhanced Hue (0..65534) and 8-bit Saturation (0..254)
if (
  colorControlTrait.supports(
    ColorControl.Command.EnhancedMoveToHueAndSaturation
  )
) {
  colorControlTrait.enhancedMoveToHueAndSaturation(
    enhancedHue = 43690u, // ~240° (Blue) on the 0..65534 scale
    saturation = 254u,    // Full saturation
    transitionTime = 15u, // 1.5 seconds (in 0.1s units)
    optionsMask = ColorControlTrait.OptionsBitmap(),
    optionsOverride = ColorControlTrait.OptionsBitmap()
  )
}
// 3. Start a hardware color loop across the device's hue range
if (colorControlTrait.supports(ColorControl.Command.ColorLoopSet)) {
  colorControlTrait.colorLoopSet(
    updateFlags =
      ColorControlTrait.UpdateFlagsBitmap(
        updateAction = true,
        updateDirection = true,
        updateTime = true,
        updateStartHue = true
      ),
    action =
      ColorControlTrait.ColorLoopActionEnum
        .ActivateFromColorLoopStartEnhancedHue,
    direction = ColorControlTrait.ColorLoopDirectionEnum.Increment,
    time = 30u, // 30 seconds per full cycle
    startHue = 0u,
    optionsMask = ColorControlTrait.OptionsBitmap(),
    optionsOverride = ColorControlTrait.OptionsBitmap()
  )
}

ExtendedColorControl is an optional Google trait on ExtendedColorLightDevice that simplifies color control by accepting color names, RGB values, or unified floating-point HSV values that combine color and brightness in a single unit.

val extendedColorControlTrait =
  extendedColorLightDevice.googleTraits.extendedColorControl ?: return
// 1. Set color by name
if (
  extendedColorControlTrait.supports(
    ExtendedColorControl.Command.MoveToColorName
  )
) {
  extendedColorControlTrait.moveToColorName(colorName = "Lavender")
}
val currentColorName = extendedColorControlTrait.currentName
// 2. Set color using 8-bit RGB values (0..255 per channel)
// Automatically coordinates brightness (LevelControl) and color (ColorControl)
if (
  extendedColorControlTrait.supports(
    ExtendedColorControl.Command.MoveToColorRgb
  )
) {
  extendedColorControlTrait.moveToColorRgb(
    red = 255u,
    green = 128u,
    blue = 0u
  )
}
val currentRed = extendedColorControlTrait.currentRed
val currentGreen = extendedColorControlTrait.currentGreen
val currentBlue = extendedColorControlTrait.currentBlue
// 3. Set color and brightness together using floating-point HSV
// hue: 0.0f..360.0f, saturation: 0.0f..1.0f, value (brightness): 0.0f..1.0f
if (
  extendedColorControlTrait.supports(
    ExtendedColorControl.Command.MoveToColorHsv
  )
) {
  extendedColorControlTrait.moveToColorHsv(
    hue = 210.0f,
    saturation = 0.85f,
    value = 0.75f
  )
}
val currentHue = extendedColorControlTrait.currentHue
val currentSaturation = extendedColorControlTrait.currentSaturation
val currentValue = extendedColorControlTrait.currentValue

Manage lighting curves

A lighting curve defines an automated schedule that smoothly transitions the brightness and optional color temperature of target lights throughout the day. For example, a lighting curve can gradually brighten lights in the morning and dim them to a warmer tone in the evening. Light device types that only support brightness, such as Dimmable Light, follow the brightness curve and ignore color temperature.

The LightingCurve trait is a structure-level Google Home platform trait. You access it from a Structure instance rather than from an individual lighting device.

Each schedule on the trait is represented by a LightingCurveSetting, which pairs a unique settingId with a LightingCurveConfig. The following table describes the configuration fields of LightingCurveConfig:

Field Description
curvePointsList A sequence of at least two CurvePoint items with distinct times. Each point specifies a time (CurveTimeOfDay with hours from 0 to 23 and minutes from 0 to 59), a brightnessPercent (0 to 100), and an optional colorTemperature in Kelvin. If colorTemperature is specified for any point, it must be a positive value for all points.
roomId The ID of the target room (for example, room@{uuid}). Applies the lighting curve to compatible dimmable and color temperature lights in that room. Specify either roomId or devices.
devices A TargetDevices object containing a list of TargetDevice entries, each with a device id and device type ID (such as home.matter.0000.types.0101 for DimmableLight or home.matter.0000.types.010c for ColorTemperatureLight). Specify either devices or roomId.
daysOfWeekList The days of the week on which the lighting curve runs (DayOfWeek). If the list is empty, the lighting curve runs daily.
adaptive Optional boolean indicating whether the lighting curve is adaptive, meaning that a target light resumes the active curve level when turned on during the scheduled window. When false, a manual change to a light disengages the light from the lighting curve for the rest of the day. When true, a light that is turned off and then turned back on during the schedule window re-engages the light with the lighting curve, causing it to conform to the curve's current brightness and color temperature, and to follow the curve from there.
enabled Optional boolean indicating whether the lighting curve setting is active. Defaults to true when creating a new setting. When enabled is omitted from an update command, the state of enabled doesn't change.

Read lighting curve settings

To inspect the lighting curves configured for a structure, retrieve the LightingCurve trait from the Structure and read its lightingCurveSettingsList attribute.

suspend fun readLightingCurves(structure: Structure) {
  val lightingCurve = structure.trait(LightingCurve).firstOrNull() ?: return

  for (setting in lightingCurve.lightingCurveSettingsList) {
    val settingId = setting.settingId
    val config = setting.config
    println("Setting ID: $settingId, enabled: ${config?.enabled}")
    config?.curvePointsList?.forEach { point ->
      println(
        "  Time: ${point.time?.hours}:${point.time?.minutes}, " +
          "Brightness: ${point.brightnessPercent}%, " +
          "ColorTemp: ${point.colorTemperature}K"
      )
    }
  }
}

Create a lighting curve setting

To create a new lighting curve schedule on a structure, construct a LightingCurveConfig with at least two CurvePoint entries, target lights (specified by roomId or devices), and the active days of the week. Then pass the configuration to createLightingCurveSetting(). The command returns the unique settingId assigned to the new lighting curve setting.

The following example creates a weekday lighting curve for a room. It ramps from 30% brightness at a warm 2700K at 7:00 AM to 80% at a cooler 4000K at 9:00 AM, then dims to 20% at a very warm 2200K by 9:00 PM:

suspend fun createRoomLightingCurve(
  structure: Structure,
  targetRoomId: String
): String? {
  val lightingCurve = structure.trait(LightingCurve).firstOrNull() ?: return null

  val curvePoints = listOf(
    LightingCurveTrait.CurvePoint(
      time = LightingCurveTrait.CurveTimeOfDay(hours = 7, minutes = 0),
      brightnessPercent = 30,
      colorTemperature = 2700
    ),
    LightingCurveTrait.CurvePoint(
      time = LightingCurveTrait.CurveTimeOfDay(hours = 9, minutes = 0),
      brightnessPercent = 80,
      colorTemperature = 4000
    ),
    LightingCurveTrait.CurvePoint(
      time = LightingCurveTrait.CurveTimeOfDay(hours = 21, minutes = 0),
      brightnessPercent = 20,
      colorTemperature = 2200
    )
  )

  val config = LightingCurveTrait.LightingCurveConfig(
    curvePointsList = curvePoints,
    roomId = targetRoomId,
    daysOfWeekList = listOf(
      DayOfWeek.MONDAY,
      DayOfWeek.TUESDAY,
      DayOfWeek.WEDNESDAY,
      DayOfWeek.THURSDAY,
      DayOfWeek.FRIDAY
    ),
    adaptive = true,
    enabled = true
  )

  // Returns the newly created settingId
  return lightingCurve.createLightingCurveSetting(config = config)
}

To target specific lighting devices instead of an entire room, provide the devices parameter using LightingCurveTrait.TargetDevices:

val targetDevices = LightingCurveTrait.TargetDevices(
  devicesList = listOf(
    LightingCurveTrait.TargetDevice(
      id = dimmableLight.id.id,
      type = DimmableLightDevice.TYPE_ID
    )
  )
)

val deviceCurveConfig = LightingCurveTrait.LightingCurveConfig(
  curvePointsList = curvePoints,
  devices = targetDevices,
  daysOfWeekList = listOf(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY),
  adaptive = true,
  enabled = true
)

val settingId = lightingCurve.createLightingCurveSetting(
  config = deviceCurveConfig
)

Update a lighting curve setting

To modify an existing lighting curve—such as changing its curve points, updating the active days of the week, or enabling and disabling the schedule—call updateLightingCurveSetting() with the target settingId and an updated LightingCurveConfig.

suspend fun updateLightingCurve(
  structure: Structure,
  settingId: String,
  updatedConfig: LightingCurveTrait.LightingCurveConfig
) {
  val lightingCurve = structure.trait(LightingCurve).firstOrNull() ?: return

  lightingCurve.updateLightingCurveSetting(
    settingId = settingId,
    config = updatedConfig
  )
}

Delete a lighting curve setting

To remove a lighting curve setting from a structure, call deleteLightingCurveSetting() with the settingId of the setting you want to delete.

suspend fun deleteLightingCurve(
  structure: Structure,
  settingId: String
) {
  val lightingCurve = structure.trait(LightingCurve).firstOrNull() ?: return

  lightingCurve.deleteLightingCurveSetting(settingId = settingId)
}