diff --git a/drivers/SmartThings/matter-switch/src/init.lua b/drivers/SmartThings/matter-switch/src/init.lua index 808247de4f..6427d1842f 100644 --- a/drivers/SmartThings/matter-switch/src/init.lua +++ b/drivers/SmartThings/matter-switch/src/init.lua @@ -87,14 +87,26 @@ local function convert_huesat_st_to_matter(val) return utils.clamp_value(math.floor((val * 0xFE) / 100.0 + 0.5), CURRENT_HUESAT_ATTR_MIN, CURRENT_HUESAT_ATTR_MAX) end -local function mired_to_kelvin(value) +local function mired_to_kelvin(value, minOrMax) if value == 0 then -- shouldn't happen, but has value = 1 log.warn(string.format("Received a color temperature of 0 mireds. Using a color temperature of 1 mired to avoid divide by zero")) end - -- we divide inside the rounding and multiply outside of it because we expect these - -- bounds to be multiples of 100 - return utils.round((MIRED_KELVIN_CONVERSION_CONSTANT / value) / 100) * 100 + -- We divide inside the rounding and multiply outside of it because we expect these + -- bounds to be multiples of 100. For the maximum mired value (minimum K value), + -- add 1 before converting and round up to nearest hundreds. For the minimum mired + -- (maximum K value) value, subtract 1 before converting and round down to nearest + -- hundreds. Note that 1 is added/subtracted from the mired value in order to avoid + -- rounding errors from the conversion of Kelvin to mireds. + local kelvin_step_size = 100 + local rounding_value = 0.5 + if minOrMax == COLOR_TEMP_MIN then + return utils.round(MIRED_KELVIN_CONVERSION_CONSTANT / (kelvin_step_size * (value + 1)) + rounding_value) * kelvin_step_size + elseif minOrMax == COLOR_TEMP_MAX then + return utils.round(MIRED_KELVIN_CONVERSION_CONSTANT / (kelvin_step_size * (value - 1)) - rounding_value) * kelvin_step_size + else + log.warn_with({hub_logs = true}, "Attempted to convert temperature unit for an undefined value") + end end --- component_to_endpoint helper function to handle situations where @@ -429,7 +441,7 @@ local mired_bounds_handler_factory = function(minOrMax) device.log.warn_with({hub_logs = true}, string.format("Device reported a color temperature %d mired outside of sane range of %.2f-%.2f", ib.data.value, COLOR_TEMPERATURE_MIRED_MIN, COLOR_TEMPERATURE_MIRED_MAX)) return end - local temp_in_kelvin = mired_to_kelvin(ib.data.value) + local temp_in_kelvin = mired_to_kelvin(ib.data.value, minOrMax) set_field_for_endpoint(device, COLOR_TEMP_BOUND_RECEIVED..minOrMax, ib.endpoint_id, temp_in_kelvin) local min = get_field_for_endpoint(device, COLOR_TEMP_BOUND_RECEIVED..COLOR_TEMP_MIN, ib.endpoint_id) local max = get_field_for_endpoint(device, COLOR_TEMP_BOUND_RECEIVED..COLOR_TEMP_MAX, ib.endpoint_id) diff --git a/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua b/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua index 6de434bd67..7de399b836 100644 --- a/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua +++ b/drivers/SmartThings/matter-switch/src/test/test_matter_switch.lua @@ -672,6 +672,33 @@ test.register_message_test( } ) +test.register_message_test( + "Min and max color temperature attributes set capability constraint using improved temperature conversion rounding", + { + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + clusters.ColorControl.attributes.ColorTempPhysicalMinMireds:build_test_report_data(mock_device, 1, 165) + } + }, + { + channel = "matter", + direction = "receive", + message = { + mock_device.id, + clusters.ColorControl.attributes.ColorTempPhysicalMaxMireds:build_test_report_data(mock_device, 1, 365) + } + }, + { + channel = "capability", + direction = "send", + message = mock_device:generate_test_message("main", capabilities.colorTemperature.colorTemperatureRange({minimum = 2800, maximum = 6000})) + } + } +) + test.register_message_test( "Min color temperature outside of range, capability not sent", {