[SmartThings Edge] Issue with the ColorTemperature default library

Hello @nayelyz,

The modification of the zigbee colorTemperatura default libraries of firmware 41.x to correct the conversion error from ºK to Mireds and back to ºK does not work quite well.

I was modifying a driver to apply this correction from the libraries and I have seen that it works well when a ºK command is sent to the device from the app or automation and then the response is handled in mireds to emit the event in ºK: see video attached

  • With this function the value in ºK (last_kelvin_set) commanded to the device is saved in storage and then it is sent to the device converted into mireds:
--- Default handler for the ColorTemperature.setColorTemperature command
---
--- This will send the move to color temperature command to the color control cluster
---
--- @param driver ZigbeeDriver The current driver running containing necessary context for execution
--- @param device st.zigbee.Device The device this message was received from containing identifying information
--- @param command CapabilityCommand The capability command table
function color_temperature_defaults.set_color_temperature(driver, device, command)
  device:set_field(LAST_KELVIN_SET .. command.component, command.args.temperature)
  switch_defaults.on(driver, device, command)
  local temp_in_mired = utils.round(CONVERSION_CONSTANT / command.args.temperature)
  device:send_to_component(command.component, zcl_clusters.ColorControl.server.commands.MoveToColorTemperature(device, temp_in_mired, 0x0000))
end
  • With this other function, the response of the device is handled in mireds and if it is not null and is within the some limits of the value in ºK saved (last_kelvin_set) in the previous function, then the value (temp_in_kelvin) is emitted as the value saved in memory (last_kelvin_set ºK).
--- Default handler for the color temperature attribute on the color control cluster
---
--- This converts the Uint16 value of the color temperature attribute on the color control cluster to
--- ColorTemperature.colorTemperature
---
--- @param driver ZigbeeDriver The current driver running containing necessary context for execution
--- @param device st.zigbee.Device The device this message was received from containing identifying information
--- @param value st.zigbee.data_types.Uint16 the color temperature value
--- @param zb_rx st.zigbee.ZigbeeMessageRx the full message this report came in
function color_temperature_defaults.color_temperature_handler(driver, device, value, zb_rx)
  local endpoint_id = zb_rx.address_header.src_endpoint.value
  local component_id = device:get_component_id_for_endpoint(endpoint_id)
  local temp_in_mired = value.value
  local last_kelvin_set = device:get_field(LAST_KELVIN_SET .. component_id)
  local temp_in_kelvin = utils.round(CONVERSION_CONSTANT / temp_in_mired)  
  -- Because we are converting from Kelvin to mireds and back, we often get rounding errors over the round trip
  -- this value substitution insures that the number the user sets in the UI matches what is generated by the event
  if last_kelvin_set ~= nil and 
    last_kelvin_set >= utils.round(CONVERSION_CONSTANT/(temp_in_mired + 1)) and last_kelvin_set <= utils.round(CONVERSION_CONSTANT/(temp_in_mired - 1)) then
    temp_in_kelvin = last_kelvin_set
  end
  device:set_field(LAST_KELVIN_SET .. component_id, nil)
  device:emit_event_for_endpoint(endpoint_id, capabilities.colorTemperature.colorTemperature(temp_in_kelvin))
end

But in this function a null value is stored in memory for the commanded ºK value (last_kelvin_set) and this I believe is not necessary and makes it work badly for a value received in a refresh command or a periodic color temperature report.
See video and its corresponding log attached

6000ºK Command sent:

2022-04-07T15:37:05.268284489+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> received Zigbee message: < ZigbeeMessageRx || 
type: 0x00, < AddressHeader || src_addr: 0x1EE7, src_endpoint: 0x01, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: ColorControl >, lqi: 0x70, rssi: -72, body_length: 0x0009, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x01, ZCLCommandId: 0x01 >, < ReadAttributeResponse || < AttributeRecord || AttributeId: 0x0007, ZclStatus: SUCCESS, DataType: Uint16, ColorTemperatureMireds: 0x00A7 > > > >
2022-04-07T15:37:05.301288156+00:00 TRACE Zigbee Light Multifunction v6  Received event with handler zigbee
2022-04-07T15:37:05.314909156+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> received Zigbee message: < ZigbeeMessageRx || 
type: 0x00, < AddressHeader || src_addr: 0x1EE7, src_endpoint: 0x01, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: OnOff >, lqi: 0x70, rssi: -72, body_length: 0x0008, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x02, ZCLCommandId: 0x01 >, < ReadAttributeResponse || < AttributeRecord || AttributeId: 0x0000, ZclStatus: SUCCESS, DataType: Boolean, OnOff: 
true > > > >
2022-04-07T15:37:05.338185156+00:00 TRACE Zigbee Light Multifunction v6  Found ZigbeeMessageDispatcher handler in zigbee_light_multifunctions
2022-04-07T15:37:05.346938489+00:00 INFO Zigbee Light Multifunction v6  Executing ZclClusterAttributeValueHandler: cluster: ColorControl, attribute: ColorTemperatureMireds
2022-04-07T15:37:05.353619822+00:00 PRINT Zigbee Light Multifunction v6  temp_in_mired >>>>>    167
2022-04-07T15:37:05.359825156+00:00 PRINT Zigbee Light Multifunction v6  last_kelvin_set >>>>>  6000
2022-04-07T15:37:05.365911156+00:00 PRINT Zigbee Light Multifunction v6  temp_in_kelvin >>>>>   5988
2022-04-07T15:37:05.371830156+00:00 PRINT Zigbee Light Multifunction v6  Emitted temp_in_kelvin >>>>>   6000
2022-04-07T15:37:05.378374489+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> emitting event: {"attribute_id":"colorTemperature","capability_id":"colorTemperature","component_id":"main","state":{"value":6000}}

Refresh command performed in app:

2022-04-07T15:37:26.003688158+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> received command: {"args":{},"capability":"refresh","command":"refresh","component":"main","positional_args":{}}
2022-04-07T15:37:26.022670158+00:00 TRACE Zigbee Light Multifunction v6  Found CapabilityCommandDispatcher handler in zigbee_light_multifunctions
2022-04-07T15:37:26.031314158+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> sending Zigbee message: < ZigbeeMessageTx || Uint16: 0x0000, < AddressHeader || src_addr: 0x0000, src_endpoint: 0x01, dest_addr: 0x1EE7, dest_endpoint: 0x01, profile: 0x0104, cluster: ColorControl >, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x00, seqno: 0x00, ZCLCommandId: 0x00 >, < ReadAttribute || AttributeId: 0x0007 > > >
2022-04-07T15:37:26.060336825+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> sending Zigbee message: < ZigbeeMessageTx || Uint16: 0x0000, < AddressHeader || src_addr: 0x0000, src_endpoint: 0x01, dest_addr: 0x1EE7, dest_endpoint: 0x01, profile: 0x0104, cluster: OnOff >, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x00, seqno: 0x00, ZCLCommandId: 0x00 >, < ReadAttribute || AttributeId: 0x0000 > > >
2022-04-07T15:37:26.074482825+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> sending Zigbee message: < ZigbeeMessageTx || Uint16: 0x0000, < AddressHeader || src_addr: 0x0000, src_endpoint: 0x01, dest_addr: 0x1EE7, dest_endpoint: 0x01, profile: 0x0104, cluster: Level >, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x00, seqno: 0x00, ZCLCommandId: 0x00 >, < ReadAttribute || AttributeId: 0x0000 > > >
2022-04-07T15:37:26.088609158+00:00 DEBUG Zigbee Light Multifunction v6  Luz H. Irene device thread event handled
2022-04-07T15:37:26.111436491+00:00 TRACE Zigbee Light Multifunction v6  Received event with handler zigbee
2022-04-07T15:37:26.131728825+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> received Zigbee message: < ZigbeeMessageRx || 
type: 0x00, < AddressHeader || src_addr: 0x1EE7, src_endpoint: 0x01, dest_addr: 0x0000, dest_endpoint: 0x01, profile: 0x0104, cluster: ColorControl >, lqi: 0x6C, rssi: -73, body_length: 0x0009, < ZCLMessageBody || < ZCLHeader || frame_ctrl: 0x18, seqno: 0x06, ZCLCommandId: 0x01 >, < ReadAttributeResponse || < AttributeRecord || AttributeId: 0x0007, ZclStatus: SUCCESS, DataType: Uint16, ColorTemperatureMireds: 0x00A7 > > > >
2022-04-07T15:37:26.162864158+00:00 TRACE Zigbee Light Multifunction v6  Found ZigbeeMessageDispatcher handler in zigbee_light_multifunctions
2022-04-07T15:37:26.171879491+00:00 INFO Zigbee Light Multifunction v6  Executing ZclClusterAttributeValueHandler: cluster: ColorControl, attribute: ColorTemperatureMireds
2022-04-07T15:37:26.179670491+00:00 PRINT Zigbee Light Multifunction v6  temp_in_mired >>>>>    167
2022-04-07T15:37:26.185571491+00:00 PRINT Zigbee Light Multifunction v6  last_kelvin_set >>>>>
2022-04-07T15:37:26.193177491+00:00 PRINT Zigbee Light Multifunction v6  temp_in_kelvin >>>>>   5988
2022-04-07T15:37:26.210383825+00:00 INFO Zigbee Light Multifunction v6  <ZigbeeDevice: a983309d-3963-4bdd-bc3b-3855f1106d14 [0x1EE7] (Luz H. Irene)> emitting event: {"attribute_id":"colorTemperature","capability_id":"colorTemperature","component_id":"main","state":{"value":5988}}

As the saved value (last_kelvin_set = nil) then the value converted from mireds to ºK is emitted and will be different from what was originally emitted.

Removing this code: device:set_field(LAST_KELVIN_SET … component_id, nil) in function color_temperature_defaults.color_temperature_handler everything works perfectly.

Also have to change the way to send color temperature commands manually. You have to add the function to save the commanded value in ºK before sending the command:

device:set_field(LAST_KELVIN_SET … command.component, command.args.temperature).

I have seen that in zigbee switch stock driver some subdrivers, which handle this manually need to be modify.

Thank you for sharing your experience with this modification. I will summarize the behavior to see if I understood it correctly:

  1. When you use the app to send commands, it works correctly, the actual value is set
  2. The capability handler set_color_temperature is saving the value received in the command’s arguments before sending this value to the device. This is called when:
    • We use the capability in the app
    • We set a routine or Rule.
    • Send a command through the API (devices endpoint)
  3. The attribute handler color_temperature_handler uses LAST_KELVIN_SET to know if the reported value is a response from the command or a regular report.

Does this statement mean that you agree with it?

ok, I see what you mean about the refresh command. I will check with the team if there’s an alternative to avoid that.

Do you mean that you need to call the capability handler set_color_temperature to set the value manually so it is calculated properly?

1 Like

The handler does not care if it is a response to a set_command, refresh or a periodic report.

If it is a response to a command, the last_kelvin_set value is needed to know that it was sent.

If it is a periodic report or refresh, the last_kelvin_set value will be the same as the one sent in the last set_color_temperature command, it should not have been set to a nil value.

Yes I agree, the same value in ºk that was sent in the command to the device is emitted to the platform, which is the purpose of the change made in the default

I mean if you don’t use the default handler to set the color temperature values and use your own handler like in this example from the stock zigbee switch / subdriver: zll-dimmer-bulb: this not will work fine

local function handle_set_color_temperature(driver, device, cmd)
   local temp_in_mired = math.floor(1000000 / cmd.args.temperature)
   device:send(OnOff.commands.On(device))
   device:send(ColorControl.commands.MoveToColorTemperature(device, temp_in_mired, 0x0000))

   local function query_device()
     do_refresh(driver, device)
   end
   device.thread:call_with_delay(2, query_device)
end

Now need to modify it to add this:
device:set_field(LAST_KELVIN_SET … command.component, command.args.temperature)

with what could be like this:

local function handle_set_color_temperature(driver, device, cmd)
   device:set_field(LAST_KELVIN_SET .. cmd.component, cmd.args.temperature)
   local temp_in_mired = utils.round(1000000 / cmd.args.temperature)
   device:send(OnOff.commands.On(device))
   device:send(ColorControl.commands.MoveToColorTemperature(device, temp_in_mired, 0x0000))

   local function query_device()
     do_refresh(driver, device)
   end
   device.thread:call_with_delay(2, query_device)
end

Hi, @Mariano_Colmenarejo.
I already reported this issue and the team will work on the fix but there’s no ETA yet, so, for now, you should keep using a custom handler for these events.

1 Like