Guía de dispositivos de iluminación

Los dispositivos de iluminación usan los atributos estándar de Matter para identificar las lámparas, activar o desactivar los estados de encendido y ajustar los niveles de brillo.

El tipo de dispositivo de luz más básico es OnOffLight, que se implementa con los atributos OnOff y Identify, y, de manera opcional, admite los atributos LevelControl y LightEffects.

Otros tipos de luces ofrecen capacidades adicionales y se implementan con diferentes rasgos:

Tipo de dispositivo de las APIs de Home Rasgos App de ejemplo de Kotlin Caso de uso

Luz de temperatura de color

ColorTemperatureLightDevice

home.matter.0000.types.010c

Un dispositivo de iluminación que se puede encender o apagar, y cuya intensidad de luz y temperatura de color se pueden ajustar.

Atributos obligatorios
     matter Identify
     matter OnOff
     matter LevelControl
     matter ColorControl

Atributos opcionales
     google LightEffects
     google ExtendedColorControl

encendido y apagado, brillo
Ligera

Luz regulable

DimmableLightDevice

home.matter.0000.types.0101

Es un dispositivo de iluminación que se puede encender o apagar, cuya intensidad de luz se puede ajustar y que se puede encender o apagar a través de un sensor de ocupación vinculado.

Atributos obligatorios
     matter Identify
     matter OnOff
     matter LevelControl

Atributos opcionales
     google LightEffects

encendido y apagado, brillo
Ligera

Luz de color extendida

ExtendedColorLightDevice

home.matter.0000.types.010d

Es un dispositivo de iluminación que se puede encender o apagar, cuya intensidad de luz y temperatura de color se pueden ajustar, y que se puede encender o apagar a través de un sensor de ocupación vinculado.

Atributos obligatorios
     matter Identify
     matter OnOff
     matter LevelControl
     matter ColorControl

Atributos opcionales
     google LightEffects
     google ExtendedColorControl

encendido y apagado, brillo
Ligera

Luz de encendido/apagado

OnOffLightDevice

home.matter.0000.types.0100

Un dispositivo de iluminación que se puede encender o apagar.

Atributos obligatorios
     matter Identify
     matter OnOff

Atributos opcionales
     matter LevelControl
     google LightEffects

encendido y apagado, brillo
Ligera

Siempre verifica la compatibilidad de atributos y comandos de un dispositivo antes de usar cualquier función o intentar actualizar los atributos. Consulta Controla dispositivos en Android para obtener más información.

Requisitos previos

Antes de trabajar con dispositivos y curvas de iluminación, asegúrate de que tu app inicialice el SDK de Home y de que incluya las importaciones requeridas:

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

Buscar dispositivos de iluminación

Para encontrar dispositivos de iluminación en una estructura, filtra la lista de dispositivos por tipo, como OnOffLightDevice y 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()

También puedes recuperar todos los dispositivos de iluminación de varios tipos de dispositivos de iluminación en un solo filtro:

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

Obtén información básica sobre un dispositivo

   Implementado en la app de ejemplo para Android   

El atributo BasicInformation incluye información como el nombre del proveedor, el ID del proveedor, el ID del producto, el nombre del producto (incluye información del modelo) y la versión de software de un dispositivo:

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

Identifica un dispositivo de iluminación

Cuando una habitación contiene varias luces, puedes ayudar a los usuarios a ubicar una lámpara física específica activando un estado de identificación visual, como hacer parpadear la luz durante unos segundos. Los cuatro tipos de dispositivos de iluminación requieren el atributo Identify.

Llama al comando identify con una duración de identifyTime en segundos para iniciar el estado de identificación. Si pasas 0, se detiene el estado de identificación de inmediato. También puedes llamar a triggerEffect para ejecutar un efecto visual específico, como Blink o 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
    )
  }
}

Verifica la conectividad de un dispositivo de iluminación

La conectividad de un dispositivo se verifica a nivel del tipo de dispositivo, ya que algunos dispositivos admiten varios tipos. El estado que se devuelve es una combinación de los estados de conectividad de todos los rasgos de ese dispositivo.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Se puede observar un estado de partiallyOnline en el caso de tipos de dispositivos mixtos cuando no hay conectividad a Internet. Es posible que los atributos estándar de Matter sigan en línea debido al enrutamiento local, pero los atributos basados en la nube estarán sin conexión.

Obtén la dirección IP del dispositivo

Para encontrar la dirección IP del dispositivo, usa el atributo networkInterfaces de GeneralDiagnosticsTrait. Las direcciones se devuelven como objetos Data, a los que puedes dar formato de strings IPv4 o IPv6 estándar con el 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
}

Cómo controlar dispositivos de iluminación

Los tipos de dispositivos OnOffLight y DimmableLight usan rasgos estándar de Matter para identificar artefactos, activar o desactivar estados de energía y ajustar los niveles de brillo.

Encender o apagar una luz

Usa el atributo OnOff para leer el estado de alimentación actual de un OnOffLight o DimmableLight, y para encender o apagar la luz.

Antes de leer el atributo onOff, verifica que el dispositivo lo admita. Algunos dispositivos funcionan como extremos de solo comando y no informan el estado.

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

Cuando onOff es true, la luz está encendida. Cuando onOff es false, la luz está apagada.

Para cambiar el estado de encendido de la luz, verifica que el rasgo admita el comando previsto y, luego, llama a on(), off() o 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
}

También puedes llamar a on() y off() directamente para establecer un estado explícito:

onOffTrait.off()
onOffTrait.on()

Para apagar una luz con una transición visual gradual, llama a offWithEffect() y especifica un valor de EffectIdentifierEnum:

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

Ajustar los niveles de brillo

Un DimmableLight requiere el atributo LevelControl, y un OnOffLight puede admitirlo de manera opcional. Usa este atributo para leer y controlar el nivel de brillo de una luz.

El atributo currentLevel informa el nivel de brillo actual en una escala de 0 a 254. También puedes inspeccionar minLevel y maxLevel para determinar el rango de brillo válido que admite el hardware.

Para establecer el brillo en un valor específico, llama a moveToLevel(). Ten en cuenta que moveToLevel() solo cambia el nivel actual cuando la luz ya está encendida, a menos que configures optionsOverride con executeIfOff. Para encender la luz automáticamente cuando se establece un nivel de brillo distinto de cero (o apagarla cuando se establece el nivel mínimo), usa moveToLevelWithOnOff().

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

En el siguiente ejemplo, se lee el nivel de brillo actual y se usa moveToLevelWithOnOff() para establecer una luz regulable en un 75% de brillo (190u) durante una transición de 1 segundo (10u décimas de segundo):

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

También puedes aumentar o disminuir el brillo en relación con el nivel actual llamando a stepWithOnOff() con StepModeEnum.Up o StepModeEnum.Down y un stepSize.

Controla el color

El atributo ColorControl está disponible en ColorTemperatureLightDevice y ExtendedColorLightDevice.

Este atributo te permite ajustar la temperatura de color en grados microrecíprocos o 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()
  )
}

También puedes establecer el color con las coordenadas de cromaticidad CIE 1931 y los valores de tono y saturación de 16 bits.

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 es un atributo opcional de Google en ExtendedColorLightDevice que simplifica el control de color, ya que acepta nombres de colores, valores RGB o valores HSV unificados de punto flotante que combinan el color y el brillo en una sola unidad.

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

Administra las curvas de iluminación

Una curva de iluminación define un programa automatizado que realiza una transición fluida del brillo y la temperatura de color opcional de las luces de destino durante el día. Por ejemplo, una curva de iluminación puede aumentar gradualmente el brillo de las luces por la mañana y atenuarlas a un tono más cálido por la noche. Los tipos de dispositivos de iluminación que solo admiten el brillo, como la luz regulable, siguen la curva de brillo y, además, ignoran la temperatura de color.

El atributo LightingCurve es un atributo Google Home platform a nivel de la estructura. Se accede a él desde una instancia de Structure, en lugar de un dispositivo de iluminación individual.

Cada programa del atributo se representa con un LightingCurveSetting, que vincula un settingId único con un LightingCurveConfig. En la siguiente tabla, se describen los campos de configuración de LightingCurveConfig:

Campo Descripción
curvePointsList Es una secuencia de, al menos, dos elementos CurvePoint con horas distintas. Cada punto especifica un time (CurveTimeOfDay con hours de 0 a 23 y minutes de 0 a 59), un brightnessPercent (de 0 a 100) y un colorTemperature opcional en Kelvin. Si se especifica colorTemperature para cualquier punto, debe ser un valor positivo para todos los puntos.
roomId Es el ID de la habitación de destino (por ejemplo, room@{uuid}). Aplica la curva de iluminación a las luces compatibles con atenuación y temperatura de color de esa habitación. Especifica roomId o devices.
devices Un objeto TargetDevices que contiene una lista de entradas TargetDevice, cada una con un id de dispositivo y un ID de type de dispositivo (como home.matter.0000.types.0101 para DimmableLight o home.matter.0000.types.010c para ColorTemperatureLight). Especifica devices o roomId.
daysOfWeekList Son los días de la semana en los que se ejecuta la curva de iluminación (DayOfWeek). Si la lista está vacía, la curva de iluminación se ejecuta a diario.
adaptive Es un valor booleano opcional que indica si la curva de iluminación es adaptable, lo que significa que una luz de destino reanuda el nivel de curva activo cuando se enciende durante el plazo programado. Cuando se establece en false, un cambio manual en una luz la desvincula de la curva de iluminación durante el resto del día. Cuando true, una luz que se apaga y se vuelve a encender durante el período de programación se vuelve a activar con la curva de iluminación, lo que hace que se ajuste al brillo y la temperatura de color actuales de la curva, y que siga la curva a partir de ese momento.
enabled Es un valor booleano opcional que indica si el parámetro de configuración de la curva de iluminación está activo. El valor predeterminado es true cuando se crea un parámetro de configuración nuevo. Cuando se omite enabled de un comando de actualización, el estado de enabled no cambia.

Cómo leer la configuración de la curva de iluminación

Para inspeccionar las curvas de iluminación configuradas para una estructura, recupera el atributo LightingCurve de Structure y lee su atributo lightingCurveSettingsList.

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

Crea un parámetro de configuración de curva de iluminación

Para crear un programa de curva de iluminación nuevo en una estructura, construye un LightingCurveConfig con al menos dos entradas CurvePoint, luces de destino (especificadas por roomId o devices) y los días activos de la semana. Luego, pasa la configuración a createLightingCurveSetting(). El comando devuelve el settingId único asignado al nuevo parámetro de configuración de la curva de iluminación.

En el siguiente ejemplo, se crea una curva de iluminación para los días de semana en una habitación. Aumenta del 30% de brillo con una temperatura cálida de 2,700 K a las 7:00 a.m. al 80% con una temperatura más fría de 4,000 K a las 9:00 a.m. Luego, se atenúa al 20% con una temperatura muy cálida de 2,200 K a las 9:00 p.m.:

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

Para segmentar dispositivos de iluminación específicos en lugar de una habitación completa, proporciona el parámetro devices con 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
)

Actualiza un parámetro de configuración de la curva de iluminación

Para modificar una curva de iluminación existente, como cambiar sus puntos de curva, actualizar los días activos de la semana o habilitar e inhabilitar el programa, llama a updateLightingCurveSetting() con el settingId de destino y un LightingCurveConfig actualizado.

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

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

Borra un parámetro de configuración de curva de iluminación

Para quitar un parámetro de configuración de la curva de iluminación de una estructura, llama a deleteLightingCurveSetting() con el settingId del parámetro de configuración que deseas borrar.

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

  lightingCurve.deleteLightingCurveSetting(settingId = settingId)
}