From ea8ea75f6239283a59ff943e07e1de5438fb2b4d Mon Sep 17 00:00:00 2001 From: nickolas-deboom <158304111+nickolas-deboom@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:22:32 -0500 Subject: [PATCH] Matter-Switch: Improve color temp conversion rounding (#1591) Matter-Switch: Improve color temp conversion rounding This change adjusts the way that the color temperature bounds are rounded while converting them from mireds into Kelvin. Previously, they were rounded to the nearest hundreds value and this sometimes resulted in the range displayed in the ST app being larger than the range supported by the device. This change will prevent this from occurring by rounding the range slightly differently such that it is within the range supported by the device. --- .../SmartThings/matter-switch/src/init.lua | 22 +++++++++++---- .../src/test/test_matter_switch.lua | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) 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", {