Make ozw CCT use device attributes instead of hard coded values (#38054)

This commit is contained in:
Patrick 2020-08-04 13:15:21 -05:00 committed by GitHub
parent 86fc977ff5
commit 0780650015
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 21 deletions

View File

@ -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,
]: ]:

View File

@ -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

View File

@ -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

View File

@ -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):