-
Notifications
You must be signed in to change notification settings - Fork 531
CHAD-12653 Zigbee: Add support for reading ColorTemperatureRange #2779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| -- Copyright 2026 SmartThings, Inc. | ||
| -- Licensed under the Apache License, Version 2.0 | ||
|
|
||
| local capabilities = require "st.capabilities" | ||
|
|
||
| return function(opts, driver, device) | ||
| if device:supports_capability(capabilities.colorTemperature) then | ||
| local subdriver = require("color_temp_range_handlers") | ||
| return true, subdriver | ||
| end | ||
| return false | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| -- Copyright 2026 SmartThings, Inc. | ||
| -- Licensed under the Apache License, Version 2.0 | ||
|
|
||
| local capabilities = require "st.capabilities" | ||
| local clusters = require "st.zigbee.zcl.clusters" | ||
| local utils = require "st.utils" | ||
| local KELVIN_MAX = "_max_kelvin" | ||
| local KELVIN_MIN = "_min_kelvin" | ||
| local MIREDS_CONVERSION_CONSTANT = 1000000 | ||
| local COLOR_TEMPERATURE_KELVIN_MAX = 15000 | ||
| local COLOR_TEMPERATURE_KELVIN_MIN = 1000 | ||
| local COLOR_TEMPERATURE_MIRED_MAX = utils.round(MIREDS_CONVERSION_CONSTANT/COLOR_TEMPERATURE_KELVIN_MIN) -- 1000 | ||
| local COLOR_TEMPERATURE_MIRED_MIN = utils.round(MIREDS_CONVERSION_CONSTANT/COLOR_TEMPERATURE_KELVIN_MAX) -- 67 | ||
|
|
||
| local function color_temp_min_mireds_handler(driver, device, value, zb_rx) | ||
| local temp_in_mired = value.value | ||
| local endpoint = zb_rx.address_header.src_endpoint.value | ||
| if temp_in_mired == nil then | ||
| return | ||
| end | ||
| if (temp_in_mired < COLOR_TEMPERATURE_MIRED_MIN or temp_in_mired > COLOR_TEMPERATURE_MIRED_MAX) then | ||
| 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)) | ||
| return | ||
| end | ||
| local temp_in_kelvin = utils.round(MIREDS_CONVERSION_CONSTANT / temp_in_mired) | ||
| device:set_field(KELVIN_MAX..endpoint, temp_in_kelvin) | ||
| local min = device:get_field(KELVIN_MIN..endpoint) | ||
| if min ~= nil then | ||
| if temp_in_kelvin > min then | ||
| device:emit_event_for_endpoint(endpoint, capabilities.colorTemperature.colorTemperatureRange({ value = {minimum = min, maximum = temp_in_kelvin}})) | ||
| else | ||
| 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)) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| local function color_temp_max_mireds_handler(driver, device, value, zb_rx) | ||
| local temp_in_mired = value.value | ||
| local endpoint = zb_rx.address_header.src_endpoint.value | ||
| if temp_in_mired == nil then | ||
| return | ||
| end | ||
| if (temp_in_mired < COLOR_TEMPERATURE_MIRED_MIN or temp_in_mired > COLOR_TEMPERATURE_MIRED_MAX) then | ||
| 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)) | ||
| return | ||
| end | ||
| local temp_in_kelvin = utils.round(MIREDS_CONVERSION_CONSTANT / temp_in_mired) | ||
| device:set_field(KELVIN_MIN..endpoint, temp_in_kelvin) | ||
| local max = device:get_field(KELVIN_MAX..endpoint) | ||
| if max ~= nil then | ||
| if temp_in_kelvin < max then | ||
| device:emit_event_for_endpoint(endpoint, capabilities.colorTemperature.colorTemperatureRange({ value = {minimum = temp_in_kelvin, maximum = max}})) | ||
| else | ||
| 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)) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| local color_temp_range_handlers = { | ||
| NAME = "Color temp range handlers", | ||
| zigbee_handlers = { | ||
| attr = { | ||
| [clusters.ColorControl.ID] = { | ||
| [clusters.ColorControl.attributes.ColorTempPhysicalMinMireds.ID] = color_temp_min_mireds_handler, | ||
| [clusters.ColorControl.attributes.ColorTempPhysicalMaxMireds.ID] = color_temp_max_mireds_handler | ||
| } | ||
| } | ||
| }, | ||
| can_handle = require("color_temp_range_handlers.can_handle") | ||
| } | ||
|
|
||
| return color_temp_range_handlers |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,4 +17,11 @@ return function(self, device) | |
| device:send(clusters.SimpleMetering.attributes.Divisor:read(device)) | ||
| device:send(clusters.SimpleMetering.attributes.Multiplier:read(device)) | ||
| end | ||
|
|
||
| if device:supports_capability(capabilities.colorTemperature) then | ||
| local clusters = require "st.zigbee.zcl.clusters" | ||
| -- min and max for color temperature | ||
| device:send(clusters.ColorControl.attributes.ColorTempPhysicalMinMireds:read(device)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what happens if these reads fail for whatever reason? This will never run again since it's in doConfigure?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you handle it in matter?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we have a concept of subscriptions, which I knew zigbee didn't have but I didn't know how it was done there. So in matter, once the subscription is set up, the device reports to us if things change, or if we re-send the subscribe.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Zigbee has attribute reporting configurations, which are essentially the same thing. Those configurations are used in the defaults, but not here. We don't expect these numbers to change basically ever over the life of the device, so it's arguably overkill having them configured to report, since that also adds them to the default refresh implementation. I'm satisfied with this implementation for the monkey patch. |
||
| device:send(clusters.ColorControl.attributes.ColorTempPhysicalMaxMireds:read(device)) | ||
| end | ||
| end | ||
Uh oh!
There was an error while loading. Please reload this page.