Light devices use standard Matter traits to identify fixtures, toggle power states, and adjust brightness levels.
The most basic light device type is the
OnOffLightDeviceType
which is implemented with the
OnOffTrait and
IdentifyTrait traits
and optionally supports the
LevelControlTrait
trait and
LightEffectsTrait
trait.
Other light types offer additional capabilities and are implemented with different traits:
| Home APIs Device Type | Traits | Swift Sample App | Use Case |
|---|---|---|---|
|
Color Temperature Light
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 IdentifyTrait matter OnOffTrait matter LevelControlTrait matter ColorControlTrait |
Light | |
|
Dimmable Light
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 IdentifyTrait matter OnOffTrait matter LevelControlTrait |
Light | |
|
Extended Color Light
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 IdentifyTrait matter OnOffTrait matter LevelControlTrait matter ColorControlTrait |
Light | |
|
On/Off Light
A lighting device that is capable of being switched on or off. |
Required Traits matter IdentifyTrait matter OnOffTrait |
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 iOS 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 Foundation import GoogleHomeSDK import GoogleHomeTypes import Network
Find light devices
To find lighting devices in a structure, filter the device list by device type,
such as
OnOffLightDeviceType
and
DimmableLightDeviceType
.
let allDevices = try await home.devices().list() // Get all On/Off Light devices in the structure let onOffLights = allDevices.filter { $0.types.contains(OnOffLightDeviceType.self) } // Get all Dimmable Light devices in the structure let dimmableLights = allDevices.filter { $0.types.contains(DimmableLightDeviceType.self) } // Retrieve a specific device type instance to access its traits let onOffLightDeviceType = await onOffLights.first?.types.get(OnOffLightDeviceType.self) let dimmableLightDeviceType = await dimmableLights.first?.types.get(DimmableLightDeviceType.self)
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) let lightDevices = try await self.home.devices().list().compactMap { $0.types.contains(DimmableLightDeviceType.self) || $0.types.contains(OnOffLightDeviceType.self) || $0.types.contains(ColorTemperatureLightDeviceType.self) || $0.types.contains(ExtendedColorLightDeviceType.self) }
Get basic information about a device
Implemented in Sample App for iOS
The BasicInformation
trait includes information like vendor name, vendor ID, product ID,
product name (includes model information), and software version for a device:
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!
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
Matter.IdentifyTrait 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.
func identifyLight(lightDeviceType: DimmableLightDeviceType) async throws {
guard let identifyTrait = lightDeviceType.matterTraits.identifyTrait else {
return
}
// Blink the light for 10 seconds so the user can locate it
if identifyTrait.supportsIdentifyCommand {
try await identifyTrait.identify(identifyTime: 10)
}
// Or trigger a specific visual identification effect
if identifyTrait.supportsTriggerEffectCommand {
try await identifyTrait.triggerEffect(
effectIdentifier: .blink,
effectVariant: .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
OnOffTrait
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.attributes.$onOff.isSupported { print("onOffTrait supports onOff state") } else { print("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 onOffTraitTest.supportsToggleCommand { print("onOffTrait supports toggle command") } else { print("onOffTrait does not support stateful toggle command") }
// Calling a command on a trait. do { try await onOffTraitTest.toggle() } catch let _ as HomeError { // Code for handling the exception }
You can also call on() and off() directly to set an explicit state:
do { try await onOffTraitTest.off() try await onOffTraitTest.on() } catch let _ as HomeError { // Code for handling the exception }
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. do { try await onOffTraitTest.offWithEffect( effectIdentifier: Matter.OnOffTrait.EffectIdentifierEnum.dyingLight, effectVariant: 0 ) } catch let _ as HomeError { // Code for handling the exception }
Adjust brightness levels
A
DimmableLight requires the
LevelControlTrait
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% do { try await levelControlTraitTest.moveToLevel( level: UInt8(127), transitionTime: 0, optionsMask: Matter.LevelControlTrait.OptionsBitmap(), optionsOverride: Matter.LevelControlTrait.OptionsBitmap() ) } catch let _ as HomeError { // Code for handling the exception }
The following example reads the current brightness level and uses
moveToLevelWithOnOff() to set a dimmable light to 75% brightness (190) over
a 1-second (10 tenths of a second) transition:
func setLightBrightness(lightDeviceType: DimmableLightDeviceType) async throws { guard let levelControl = lightDeviceType.matterTraits.levelControlTrait else { return } // Read the current brightness level (0 to 254) let currentLevel: UInt8? = levelControl.attributes.currentLevel print("Current brightness level: \(String(describing: currentLevel))") // Move to ~75% brightness (190 out of 254) and turn on the light if it is off if levelControl.supportsMoveToLevelWithOnOffCommand { try await levelControl.moveToLevelWithOnOff( level: UInt8(190), transitionTime: 10, optionsMask: Matter.LevelControlTrait.OptionsBitmap(), optionsOverride: Matter.LevelControlTrait.OptionsBitmap() ) } }
You can also increment or decrement brightness relative to the current level by
calling stepWithOnOff() with .up or .down and a stepSize.
Control color
TheColorControlTrait
trait is available on both the
ColorTemperatureLightDeviceType
and
ExtendedColorLightDeviceType.
This trait lets you adjust color temperature in micro-reciprocal degrees or mireds.
guard let colorControlTrait = colorTempLightDeviceType.matterTraits.colorControlTrait else { 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) let currentMireds = colorControlTrait.attributes.colorTemperatureMireds let minMireds = colorControlTrait.attributes.colorTempPhysicalMinMireds ?? 153 let maxMireds = colorControlTrait.attributes.colorTempPhysicalMaxMireds ?? 500 // Clamp target (370 mireds ≈ 2700K) to the device's physical bounds let targetMireds = min(max(UInt16(370), minMireds), maxMireds) if colorControlTrait.supportsMoveToColorTemperatureCommand { try await colorControlTrait.moveToColorTemperature( colorTemperatureMireds: targetMireds, transitionTime: 20, // 2.0 seconds (in 0.1s units) optionsMask: Matter.ColorControlTrait.OptionsBitmap(), optionsOverride: Matter.ColorControlTrait.OptionsBitmap() ) }
You can also set color using CIE 1931 chromaticity coordinates and 16-bit hue and saturation values.
guard let colorControlTrait = extendedColorLightDeviceType.matterTraits.colorControlTrait else { 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.supportsMoveToColorCommand { try await colorControlTrait.moveToColor( colorX: 20493, colorY: 21561, transitionTime: 10, // 1.0 second (in 0.1s units) optionsMask: Matter.ColorControlTrait.OptionsBitmap(), optionsOverride: Matter.ColorControlTrait.OptionsBitmap() ) } let currentX = colorControlTrait.attributes.currentX let currentY = colorControlTrait.attributes.currentY // 2. Move to 16-bit Enhanced Hue (0..65534) and 8-bit Saturation (0..254) if colorControlTrait.supportsEnhancedMoveToHueAndSaturationCommand { try await colorControlTrait.enhancedMoveToHueAndSaturation( enhancedHue: 43690, // ~240° (Blue) on the 0..65534 scale saturation: 254, // Full saturation transitionTime: 15, // 1.5 seconds (in 0.1s units) optionsMask: Matter.ColorControlTrait.OptionsBitmap(), optionsOverride: Matter.ColorControlTrait.OptionsBitmap() ) } // 3. Start a hardware color loop across the device's hue range if colorControlTrait.supportsColorLoopSetCommand { try await colorControlTrait.colorLoopSet( updateFlags: [ .updateAction, .updateDirection, .updateTime, .updateStartHue ], action: .activateFromColorLoopStartEnhancedHue, direction: .increment, time: 30, // 30 seconds per full cycle startHue: 0, optionsMask: Matter.ColorControlTrait.OptionsBitmap(), optionsOverride: Matter.ColorControlTrait.OptionsBitmap() ) }
Google.ExtendedColorControlTrait
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.
guard let extendedColorControlTrait = extendedColorLightDeviceType.googleTraits.extendedColorControlTrait else { return } // 1. Set color by name if extendedColorControlTrait.supportsMoveToColorNameCommand { try await extendedColorControlTrait.moveToColorName(colorName: "Lavender") } let currentColorName = extendedColorControlTrait.attributes.currentName // 2. Set color using 8-bit RGB values (0..255 per channel) // Automatically coordinates brightness (LevelControl) and color (ColorControl) if extendedColorControlTrait.supportsMoveToColorRGBCommand { try await extendedColorControlTrait.moveToColorRGB( red: 255, green: 128, blue: 0 ) } let currentRed = extendedColorControlTrait.attributes.currentRed let currentGreen = extendedColorControlTrait.attributes.currentGreen let currentBlue = extendedColorControlTrait.attributes.currentBlue // 3. Set color and brightness together using floating-point HSV // hue: 0.0...360.0, saturation: 0.0...1.0, value (brightness): 0.0...1.0 if extendedColorControlTrait.supportsMoveToColorHSVCommand { try await extendedColorControlTrait.moveToColorHSV( hue: 210.0, saturation: 0.85, value: 0.75 ) } let currentHue = extendedColorControlTrait.attributes.currentHue let currentSaturation = extendedColorControlTrait.attributes.currentSaturation let currentValue = extendedColorControlTrait.attributes.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
Google.LightingCurveTrait
trait is a structure-level
Google Home platform (GHP) 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 |
|---|---|
curvePointsArray |
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. |
daysOfWeekArray |
The days of the week on which the lighting curve runs (Locale.Weekday). 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
Google.LightingCurveTrait
trait from the Structure and read its
lightingCurveSettingsArray
attribute.
func readLightingCurves(structure: Structure) async {
guard let lightingCurve = await structure.traits.get(
Google.LightingCurveTrait.self
) else {
return
}
for setting in lightingCurve.attributes.lightingCurveSettingsArray {
let settingId = setting.settingId
let config = setting.config
print(
"Setting ID: \(String(describing: settingId)), " +
"enabled: \(String(describing: config?.enabled))"
)
for point in config?.curvePointsArray ?? [] {
print(
" Time: \(point.time?.hours ?? 0):\(point.time?.minutes ?? 0), " +
"Brightness: \(point.brightnessPercent ?? 0)%, " +
"ColorTemp: \(point.colorTemperature ?? 0)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 that ramps brightness from 30% at 7:00 AM to 80% at 9:00 AM and dims to 20% at 9:00 PM:
func createRoomLightingCurve(
structure: Structure,
targetRoomId: String
) async throws -> String? {
guard let lightingCurve = await structure.traits.get(
Google.LightingCurveTrait.self
) else {
return nil
}
let curvePoints = [
Google.LightingCurveTrait.CurvePoint(
time: Google.LightingCurveTrait.CurveTimeOfDay(hours: 7, minutes: 0),
brightnessPercent: 30,
colorTemperature: 2700
),
Google.LightingCurveTrait.CurvePoint(
time: Google.LightingCurveTrait.CurveTimeOfDay(hours: 9, minutes: 0),
brightnessPercent: 80,
colorTemperature: 4000
),
Google.LightingCurveTrait.CurvePoint(
time: Google.LightingCurveTrait.CurveTimeOfDay(hours: 21, minutes: 0),
brightnessPercent: 20,
colorTemperature: 2200
),
]
let config = Google.LightingCurveTrait.LightingCurveConfig(
curvePointsArray: curvePoints,
roomId: targetRoomId,
daysOfWeekArray: [
.monday,
.tuesday,
.wednesday,
.thursday,
.friday,
],
adaptive: true,
enabled: true
)
let response = try await lightingCurve.createLightingCurveSetting(
config: config
)
return response.settingId
}
To target specific lighting devices instead of an entire room, provide the
devices parameter using Google.LightingCurveTrait.TargetDevices:
let targetDevices = Google.LightingCurveTrait.TargetDevices(
devicesArray: [
Google.LightingCurveTrait.TargetDevice(
id: dimmableLight.id,
type: DimmableLightDeviceType.identifier
)
]
)
let deviceCurveConfig = Google.LightingCurveTrait.LightingCurveConfig(
curvePointsArray: curvePoints,
devices: targetDevices,
daysOfWeekArray: [.saturday, .sunday],
adaptive: true,
enabled: true
)
let response = try await lightingCurve.createLightingCurveSetting(
config: deviceCurveConfig
)
let settingId = response.settingId
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.
func updateLightingCurve(
structure: Structure,
settingId: String,
updatedConfig: Google.LightingCurveTrait.LightingCurveConfig
) async throws {
guard let lightingCurve = await structure.traits.get(
Google.LightingCurveTrait.self
) else {
return
}
_ = try await 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.
func deleteLightingCurve(
structure: Structure,
settingId: String
) async throws {
guard let lightingCurve = await structure.traits.get(
Google.LightingCurveTrait.self
) else {
return
}
_ = try await lightingCurve.deleteLightingCurveSetting(settingId: settingId)
}