|
| 1 | +-- Copyright 2026 SmartThings, Inc. |
| 2 | +-- Licensed under the Apache License, Version 2.0 |
| 3 | + |
| 4 | +local capabilities = require "st.capabilities" |
| 5 | +local clusters = require "st.zigbee.zcl.clusters" |
| 6 | +local utils = require "st.utils" |
| 7 | +local KELVIN_MAX = "_max_kelvin" |
| 8 | +local KELVIN_MIN = "_min_kelvin" |
| 9 | +local MIREDS_CONVERSION_CONSTANT = 1000000 |
| 10 | +local COLOR_TEMPERATURE_KELVIN_MAX = 15000 |
| 11 | +local COLOR_TEMPERATURE_KELVIN_MIN = 1000 |
| 12 | +local COLOR_TEMPERATURE_MIRED_MAX = utils.round(MIREDS_CONVERSION_CONSTANT/COLOR_TEMPERATURE_KELVIN_MIN) -- 1000 |
| 13 | +local COLOR_TEMPERATURE_MIRED_MIN = utils.round(MIREDS_CONVERSION_CONSTANT/COLOR_TEMPERATURE_KELVIN_MAX) -- 67 |
| 14 | + |
| 15 | +local function color_temp_min_mireds_handler(driver, device, value, zb_rx) |
| 16 | + local temp_in_mired = value.value |
| 17 | + local endpoint = zb_rx.address_header.src_endpoint.value |
| 18 | + if temp_in_mired == nil then |
| 19 | + return |
| 20 | + end |
| 21 | + if (temp_in_mired < COLOR_TEMPERATURE_MIRED_MIN or temp_in_mired > COLOR_TEMPERATURE_MIRED_MAX) then |
| 22 | + device.log.warn_with({hub_logs = true}, string.format("Device reported a color temperature %d mired outside of sane range of %.2f-%.2f", temp_in_mired, COLOR_TEMPERATURE_MIRED_MIN, COLOR_TEMPERATURE_MIRED_MAX)) |
| 23 | + return |
| 24 | + end |
| 25 | + local temp_in_kelvin = utils.round(MIREDS_CONVERSION_CONSTANT / temp_in_mired) |
| 26 | + device:set_field(KELVIN_MAX..endpoint, temp_in_kelvin) |
| 27 | + local min = device:get_field(KELVIN_MIN..endpoint) |
| 28 | + if min ~= nil then |
| 29 | + if temp_in_kelvin > min then |
| 30 | + device:emit_event_for_endpoint(endpoint, capabilities.colorTemperature.colorTemperatureRange({ value = {minimum = min, maximum = temp_in_kelvin}})) |
| 31 | + else |
| 32 | + device.log.warn_with({hub_logs = true}, string.format("Device reported a max color temperature %d K that is not higher than the reported min color temperature %d K", min, temp_in_kelvin)) |
| 33 | + end |
| 34 | + end |
| 35 | +end |
| 36 | + |
| 37 | +local function color_temp_max_mireds_handler(driver, device, value, zb_rx) |
| 38 | + local temp_in_mired = value.value |
| 39 | + local endpoint = zb_rx.address_header.src_endpoint.value |
| 40 | + if temp_in_mired == nil then |
| 41 | + return |
| 42 | + end |
| 43 | + if (temp_in_mired < COLOR_TEMPERATURE_MIRED_MIN or temp_in_mired > COLOR_TEMPERATURE_MIRED_MAX) then |
| 44 | + device.log.warn_with({hub_logs = true}, string.format("Device reported a color temperature %d mired outside of sane range of %.2f-%.2f", temp_in_mired, COLOR_TEMPERATURE_MIRED_MIN, COLOR_TEMPERATURE_MIRED_MAX)) |
| 45 | + return |
| 46 | + end |
| 47 | + local temp_in_kelvin = utils.round(MIREDS_CONVERSION_CONSTANT / temp_in_mired) |
| 48 | + device:set_field(KELVIN_MIN..endpoint, temp_in_kelvin) |
| 49 | + local max = device:get_field(KELVIN_MAX..endpoint) |
| 50 | + if max ~= nil then |
| 51 | + if temp_in_kelvin < max then |
| 52 | + device:emit_event_for_endpoint(endpoint, capabilities.colorTemperature.colorTemperatureRange({ value = {minimum = temp_in_kelvin, maximum = max}})) |
| 53 | + else |
| 54 | + device.log.warn_with({hub_logs = true}, string.format("Device reported a min color temperature %d K that is not lower than the reported max color temperature %d K", temp_in_kelvin, max)) |
| 55 | + end |
| 56 | + end |
| 57 | +end |
| 58 | + |
| 59 | +local color_temp_range_handlers = { |
| 60 | + NAME = "Color temp range handlers", |
| 61 | + zigbee_handlers = { |
| 62 | + attr = { |
| 63 | + [clusters.ColorControl.ID] = { |
| 64 | + [clusters.ColorControl.attributes.ColorTempPhysicalMinMireds.ID] = color_temp_min_mireds_handler, |
| 65 | + [clusters.ColorControl.attributes.ColorTempPhysicalMaxMireds.ID] = color_temp_max_mireds_handler |
| 66 | + } |
| 67 | + } |
| 68 | + }, |
| 69 | + can_handle = require("color_temp_range_handlers.can_handle") |
| 70 | +} |
| 71 | + |
| 72 | +return color_temp_range_handlers |
0 commit comments