mirror of
https://github.com/home-assistant/core.git
synced 2025-07-10 14:57:09 +00:00
Make ozw CCT use device attributes instead of hard coded values (#38054)
This commit is contained in:
parent
86fc977ff5
commit
0780650015
@ -114,7 +114,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
|
|
||||||
# Filter out CommandClasses we're definitely not interested in.
|
# Filter out CommandClasses we're definitely not interested in.
|
||||||
if value.command_class in [
|
if value.command_class in [
|
||||||
CommandClass.CONFIGURATION,
|
|
||||||
CommandClass.VERSION,
|
CommandClass.VERSION,
|
||||||
CommandClass.MANUFACTURER_SPECIFIC,
|
CommandClass.MANUFACTURER_SPECIFIC,
|
||||||
]:
|
]:
|
||||||
|
@ -250,6 +250,16 @@ DISCOVERY_SCHEMAS = (
|
|||||||
const.DISC_INDEX: ValueIndex.SWITCH_COLOR_CHANNELS,
|
const.DISC_INDEX: ValueIndex.SWITCH_COLOR_CHANNELS,
|
||||||
const.DISC_OPTIONAL: True,
|
const.DISC_OPTIONAL: True,
|
||||||
},
|
},
|
||||||
|
"min_kelvin": {
|
||||||
|
const.DISC_COMMAND_CLASS: (CommandClass.CONFIGURATION,),
|
||||||
|
const.DISC_INDEX: 81, # PR for upstream to add SWITCH_COLOR_CT_WARM
|
||||||
|
const.DISC_OPTIONAL: True,
|
||||||
|
},
|
||||||
|
"max_kelvin": {
|
||||||
|
const.DISC_COMMAND_CLASS: (CommandClass.CONFIGURATION,),
|
||||||
|
const.DISC_INDEX: 82, # PR for upstream to add SWITCH_COLOR_CT_COLD
|
||||||
|
const.DISC_OPTIONAL: True,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ # All other text/numeric sensors
|
{ # All other text/numeric sensors
|
||||||
|
@ -30,9 +30,6 @@ COLOR_CHANNEL_COLD_WHITE = 0x02
|
|||||||
COLOR_CHANNEL_RED = 0x04
|
COLOR_CHANNEL_RED = 0x04
|
||||||
COLOR_CHANNEL_GREEN = 0x08
|
COLOR_CHANNEL_GREEN = 0x08
|
||||||
COLOR_CHANNEL_BLUE = 0x10
|
COLOR_CHANNEL_BLUE = 0x10
|
||||||
TEMP_COLOR_MAX = 500 # mired equivalent to 2000K
|
|
||||||
TEMP_COLOR_MIN = 154 # mired equivalent to 6500K
|
|
||||||
TEMP_COLOR_DIFF = TEMP_COLOR_MAX - TEMP_COLOR_MIN
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
@ -71,6 +68,9 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
self._white = None
|
self._white = None
|
||||||
self._ct = None
|
self._ct = None
|
||||||
self._supported_features = SUPPORT_BRIGHTNESS
|
self._supported_features = SUPPORT_BRIGHTNESS
|
||||||
|
self._min_mireds = 153 # 6500K as a safe default
|
||||||
|
self._max_mireds = 370 # 2700K as a safe default
|
||||||
|
|
||||||
# make sure that supported features is correctly set
|
# make sure that supported features is correctly set
|
||||||
self.on_value_update()
|
self.on_value_update()
|
||||||
|
|
||||||
@ -136,6 +136,16 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
"""Return the color temperature."""
|
"""Return the color temperature."""
|
||||||
return self._ct
|
return self._ct
|
||||||
|
|
||||||
|
@property
|
||||||
|
def min_mireds(self):
|
||||||
|
"""Return the coldest color_temp that this light supports."""
|
||||||
|
return self._min_mireds
|
||||||
|
|
||||||
|
@property
|
||||||
|
def max_mireds(self):
|
||||||
|
"""Return the warmest color_temp that this light supports."""
|
||||||
|
return self._max_mireds
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_set_duration(self, **kwargs):
|
def async_set_duration(self, **kwargs):
|
||||||
"""Set the transition time for the brightness value.
|
"""Set the transition time for the brightness value.
|
||||||
@ -209,7 +219,11 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
0,
|
0,
|
||||||
min(
|
min(
|
||||||
255,
|
255,
|
||||||
round((TEMP_COLOR_MAX - round(color_temp)) / TEMP_COLOR_DIFF * 255),
|
round(
|
||||||
|
(self._max_mireds - color_temp)
|
||||||
|
/ (self._max_mireds - self._min_mireds)
|
||||||
|
* 255
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
warm = 255 - cold
|
warm = 255 - cold
|
||||||
@ -241,16 +255,26 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
# Color Data String
|
# Color Data String
|
||||||
data = self.values.color.data[ATTR_VALUE]
|
data = self.values.color.data[ATTR_VALUE]
|
||||||
|
|
||||||
# RGB is always present in the openzwave color data string.
|
# RGB is always present in the OpenZWave color data string.
|
||||||
rgb = [int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)]
|
rgb = [int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)]
|
||||||
self._hs = color_util.color_RGB_to_hs(*rgb)
|
self._hs = color_util.color_RGB_to_hs(*rgb)
|
||||||
|
|
||||||
# Parse remaining color channels. Openzwave appends white channels
|
# Parse remaining color channels. OpenZWave appends white channels
|
||||||
# that are present.
|
# that are present.
|
||||||
index = 7
|
index = 7
|
||||||
temp_warm = 0
|
temp_warm = 0
|
||||||
temp_cold = 0
|
temp_cold = 0
|
||||||
|
|
||||||
|
# Update color temp limits.
|
||||||
|
if self.values.min_kelvin:
|
||||||
|
self._max_mireds = color_util.color_temperature_kelvin_to_mired(
|
||||||
|
self.values.min_kelvin.data[ATTR_VALUE]
|
||||||
|
)
|
||||||
|
if self.values.max_kelvin:
|
||||||
|
self._min_mireds = color_util.color_temperature_kelvin_to_mired(
|
||||||
|
self.values.max_kelvin.data[ATTR_VALUE]
|
||||||
|
)
|
||||||
|
|
||||||
# Warm white
|
# Warm white
|
||||||
if self._color_channels & COLOR_CHANNEL_WARM_WHITE:
|
if self._color_channels & COLOR_CHANNEL_WARM_WHITE:
|
||||||
self._white = int(data[index : index + 2], 16)
|
self._white = int(data[index : index + 2], 16)
|
||||||
@ -264,13 +288,12 @@ class ZwaveLight(ZWaveDeviceEntity, LightEntity):
|
|||||||
temp_cold = self._white
|
temp_cold = self._white
|
||||||
|
|
||||||
# Calculate color temps based on white LED status
|
# Calculate color temps based on white LED status
|
||||||
if temp_cold > 0:
|
if temp_cold or temp_warm:
|
||||||
self._ct = round(TEMP_COLOR_MAX - ((temp_cold / 255) * TEMP_COLOR_DIFF))
|
self._ct = round(
|
||||||
# Only used if CW channel missing
|
self._max_mireds
|
||||||
elif temp_warm > 0:
|
- ((temp_cold / 255) * (self._max_mireds - self._min_mireds))
|
||||||
self._ct = round(TEMP_COLOR_MAX - temp_warm)
|
)
|
||||||
|
|
||||||
# If no rgb channels supported, report None.
|
|
||||||
if not (
|
if not (
|
||||||
self._color_channels & COLOR_CHANNEL_RED
|
self._color_channels & COLOR_CHANNEL_RED
|
||||||
or self._color_channels & COLOR_CHANNEL_GREEN
|
or self._color_channels & COLOR_CHANNEL_GREEN
|
||||||
|
@ -284,7 +284,7 @@ async def test_light(hass, light_data, light_msg, light_rgb_msg, sent_messages):
|
|||||||
assert state.attributes["xy_color"] == (0.519, 0.429)
|
assert state.attributes["xy_color"] == (0.519, 0.429)
|
||||||
|
|
||||||
# Test setting color temp
|
# Test setting color temp
|
||||||
new_color = 465
|
new_color = 200
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"light",
|
"light",
|
||||||
"turn_on",
|
"turn_on",
|
||||||
@ -298,14 +298,14 @@ async def test_light(hass, light_data, light_msg, light_rgb_msg, sent_messages):
|
|||||||
|
|
||||||
msg = sent_messages[-2]
|
msg = sent_messages[-2]
|
||||||
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
||||||
assert msg["payload"] == {"Value": "#000000e51a", "ValueIDKey": 659341335}
|
assert msg["payload"] == {"Value": "#00000037c8", "ValueIDKey": 659341335}
|
||||||
|
|
||||||
# Feedback on state
|
# Feedback on state
|
||||||
light_msg.decode()
|
light_msg.decode()
|
||||||
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
|
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
|
||||||
light_msg.encode()
|
light_msg.encode()
|
||||||
light_rgb_msg.decode()
|
light_rgb_msg.decode()
|
||||||
light_rgb_msg.payload["Value"] = "#000000e51a"
|
light_rgb_msg.payload["Value"] = "#00000037c8"
|
||||||
light_rgb_msg.encode()
|
light_rgb_msg.encode()
|
||||||
receive_message(light_msg)
|
receive_message(light_msg)
|
||||||
receive_message(light_rgb_msg)
|
receive_message(light_rgb_msg)
|
||||||
@ -314,7 +314,7 @@ async def test_light(hass, light_data, light_msg, light_rgb_msg, sent_messages):
|
|||||||
state = hass.states.get("light.led_bulb_6_multi_colour_level")
|
state = hass.states.get("light.led_bulb_6_multi_colour_level")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
assert state.attributes["color_temp"] == 465
|
assert state.attributes["color_temp"] == 200
|
||||||
|
|
||||||
# Test setting invalid color temp
|
# Test setting invalid color temp
|
||||||
new_color = 120
|
new_color = 120
|
||||||
@ -347,7 +347,7 @@ async def test_light(hass, light_data, light_msg, light_rgb_msg, sent_messages):
|
|||||||
state = hass.states.get("light.led_bulb_6_multi_colour_level")
|
state = hass.states.get("light.led_bulb_6_multi_colour_level")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
assert state.attributes["color_temp"] == 154
|
assert state.attributes["color_temp"] == 153
|
||||||
|
|
||||||
|
|
||||||
async def test_no_rgb_light(hass, light_no_rgb_data, light_no_rgb_msg, sent_messages):
|
async def test_no_rgb_light(hass, light_no_rgb_data, light_no_rgb_msg, sent_messages):
|
||||||
@ -486,6 +486,9 @@ async def test_wc_light(hass, light_wc_data, light_msg, light_rgb_msg, sent_mess
|
|||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "off"
|
assert state.state == "off"
|
||||||
|
|
||||||
|
assert state.attributes["min_mireds"] == 153
|
||||||
|
assert state.attributes["max_mireds"] == 370
|
||||||
|
|
||||||
# Turn on the light
|
# Turn on the light
|
||||||
new_color = 190
|
new_color = 190
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
@ -497,14 +500,14 @@ async def test_wc_light(hass, light_wc_data, light_msg, light_rgb_msg, sent_mess
|
|||||||
assert len(sent_messages) == 2
|
assert len(sent_messages) == 2
|
||||||
msg = sent_messages[-2]
|
msg = sent_messages[-2]
|
||||||
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
||||||
assert msg["payload"] == {"Value": "#0000001be4", "ValueIDKey": 659341335}
|
assert msg["payload"] == {"Value": "#0000002bd4", "ValueIDKey": 659341335}
|
||||||
|
|
||||||
# Feedback on state
|
# Feedback on state
|
||||||
light_msg.decode()
|
light_msg.decode()
|
||||||
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
|
light_msg.payload["Value"] = byte_to_zwave_brightness(255)
|
||||||
light_msg.encode()
|
light_msg.encode()
|
||||||
light_rgb_msg.decode()
|
light_rgb_msg.decode()
|
||||||
light_rgb_msg.payload["Value"] = "#0000001be4"
|
light_rgb_msg.payload["Value"] = "#0000002bd4"
|
||||||
light_rgb_msg.encode()
|
light_rgb_msg.encode()
|
||||||
receive_message(light_msg)
|
receive_message(light_msg)
|
||||||
receive_message(light_rgb_msg)
|
receive_message(light_rgb_msg)
|
||||||
@ -513,7 +516,7 @@ async def test_wc_light(hass, light_wc_data, light_msg, light_rgb_msg, sent_mess
|
|||||||
state = hass.states.get("light.led_bulb_6_multi_colour_level")
|
state = hass.states.get("light.led_bulb_6_multi_colour_level")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
assert state.attributes["color_temp"] == 191
|
assert state.attributes["color_temp"] == 190
|
||||||
|
|
||||||
|
|
||||||
async def test_new_ozw_light(hass, light_new_ozw_data, light_msg, sent_messages):
|
async def test_new_ozw_light(hass, light_new_ozw_data, light_msg, sent_messages):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user