From 11009b99bdc467a1bfeb8e1ffe247c24cfa25ef6 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Mon, 25 Jan 2021 22:09:12 +0100 Subject: [PATCH] Improve zwave_js light targetvalue vs currentValue selection (#45477) --- homeassistant/components/zwave_js/light.py | 20 +- tests/components/zwave_js/conftest.py | 14 + tests/components/zwave_js/test_light.py | 11 + .../zwave_js/eaton_rf9640_dimmer_state.json | 782 ++++++++++++++++++ 4 files changed, 822 insertions(+), 5 deletions(-) create mode 100644 tests/fixtures/zwave_js/eaton_rf9640_dimmer_state.json diff --git a/homeassistant/components/zwave_js/light.py b/homeassistant/components/zwave_js/light.py index 101782339295..595f8f50cdcc 100644 --- a/homeassistant/components/zwave_js/light.py +++ b/homeassistant/components/zwave_js/light.py @@ -105,7 +105,13 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity): Z-Wave multilevel switches use a range of [0, 99] to control brightness. """ - if self._target_value is not None and self._target_value.value is not None: + # prefer targetValue only if CC Version >= 4 + # otherwise use currentValue (pre V4 dimmers) + if ( + self._target_value + and self._target_value.value is not None + and self._target_value.cc_version >= 4 + ): return round((self._target_value.value / 99) * 255) if self.info.primary_value.value is not None: return round((self.info.primary_value.value / 99) * 255) @@ -237,7 +243,7 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity): if self.info.primary_value.value == zwave_brightness: # no point in setting same brightness return - # set transition value before seinding new brightness + # set transition value before sending new brightness await self._async_set_transition_duration(transition) # setting a value requires setting targetValue await self.info.node.async_set_value(self._target_value, zwave_brightness) @@ -324,7 +330,11 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity): ) else: self._color_temp = None - elif ww_val or cw_val: - # only one white channel + elif ww_val: + # only one white channel (warm white) self._supports_white_value = True - # FIXME: Update self._white_value + self._white_value = ww_val.value + elif cw_val: + # only one white channel (cool white) + self._supports_white_value = True + self._white_value = cw_val.value diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index be0390ab0470..7774037b480c 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -62,6 +62,12 @@ def bulb_6_multi_color_state_fixture(): return json.loads(load_fixture("zwave_js/bulb_6_multi_color_state.json")) +@pytest.fixture(name="eaton_rf9640_dimmer_state", scope="session") +def eaton_rf9640_dimmer_state_fixture(): + """Load the bulb 6 multi-color node state fixture data.""" + return json.loads(load_fixture("zwave_js/eaton_rf9640_dimmer_state.json")) + + @pytest.fixture(name="lock_schlage_be469_state", scope="session") def lock_schlage_be469_state_fixture(): """Load the schlage lock node state fixture data.""" @@ -168,6 +174,14 @@ def bulb_6_multi_color_fixture(client, bulb_6_multi_color_state): return node +@pytest.fixture(name="eaton_rf9640_dimmer") +def eaton_rf9640_dimmer_fixture(client, eaton_rf9640_dimmer_state): + """Mock a Eaton RF9640 (V4 compatible) dimmer node.""" + node = Node(client, eaton_rf9640_dimmer_state) + client.driver.controller.nodes[node.node_id] = node + return node + + @pytest.fixture(name="lock_schlage_be469") def lock_schlage_be469_fixture(client, lock_schlage_be469_state): """Mock a schlage lock node.""" diff --git a/tests/components/zwave_js/test_light.py b/tests/components/zwave_js/test_light.py index 85cf42ee0f02..56c008e8132c 100644 --- a/tests/components/zwave_js/test_light.py +++ b/tests/components/zwave_js/test_light.py @@ -13,6 +13,7 @@ from homeassistant.components.light import ( from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_OFF, STATE_ON BULB_6_MULTI_COLOR_LIGHT_ENTITY = "light.bulb_6_multi_color_current_value" +EATON_RF9640_ENTITY = "light.allloaddimmer_current_value" async def test_light(hass, client, bulb_6_multi_color, integration): @@ -375,3 +376,13 @@ async def test_light(hass, client, bulb_6_multi_color, integration): }, } assert args["value"] == 0 + + +async def test_v4_dimmer_light(hass, client, eaton_rf9640_dimmer, integration): + """Test a light that supports MultiLevelSwitch CommandClass version 4.""" + state = hass.states.get(EATON_RF9640_ENTITY) + + assert state + assert state.state == STATE_ON + # the light should pick targetvalue which has zwave value 20 + assert state.attributes[ATTR_BRIGHTNESS] == 52 diff --git a/tests/fixtures/zwave_js/eaton_rf9640_dimmer_state.json b/tests/fixtures/zwave_js/eaton_rf9640_dimmer_state.json new file mode 100644 index 000000000000..38cbb63b1c6c --- /dev/null +++ b/tests/fixtures/zwave_js/eaton_rf9640_dimmer_state.json @@ -0,0 +1,782 @@ +{ + "nodeId": 19, + "index": 0, + "installerIcon": 1536, + "userIcon": 1536, + "status": 4, + "ready": true, + "deviceClass": { + "basic": "Routing Slave", + "generic": "Multilevel Switch", + "specific": "Multilevel Power Switch", + "mandatorySupportedCCs": [ + "Basic", + "Multilevel Switch", + "All Switch" + ], + "mandatoryControlCCs": [] + }, + "isListening": true, + "isFrequentListening": false, + "isRouting": true, + "maxBaudRate": 40000, + "isSecure": false, + "version": 4, + "isBeaming": true, + "manufacturerId": 26, + "productId": 1281, + "productType": 17481, + "firmwareVersion": "1.0", + "zwavePlusVersion": 1, + "nodeType": 0, + "roleType": 5, + "name": "AllLoadDimmer", + "location": "", + "deviceConfig": { + "manufacturerId": 26, + "manufacturer": "Eaton", + "label": "RF9640", + "description": "Z-Wave Plus universal smart dimmer", + "devices": [ + { + "productType": "0x4449", + "productId": "0x0501" + } + ], + "firmwareVersion": { + "min": "0.0", + "max": "255.255" + }, + "paramInformation": { + "_map": {} + } + }, + "label": "RF9640", + "neighbors": [ + 4, + 8, + 9, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18 + ], + "interviewAttempts": 1, + "endpoints": [ + { + "nodeId": 19, + "index": 0, + "installerIcon": 1536, + "userIcon": 1536 + } + ], + "values": [ + { + "commandClassName": "Multilevel Switch", + "commandClass": 38, + "endpoint": 0, + "property": "targetValue", + "propertyName": "targetValue", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 0, + "max": 99, + "label": "Target value" + }, + "value": 20, + "ccVersion": 4 + }, + { + "commandClassName": "Multilevel Switch", + "commandClass": 38, + "endpoint": 0, + "property": "duration", + "propertyName": "duration", + "metadata": { + "type": "duration", + "readable": true, + "writeable": true, + "label": "Transition duration" + }, + "value": { + "value": 0, + "unit": "seconds" + }, + "ccVersion": 4 + }, + { + "commandClassName": "Multilevel Switch", + "commandClass": 38, + "endpoint": 0, + "property": "currentValue", + "propertyName": "currentValue", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 99, + "label": "Current value" + }, + "value": 0, + "ccVersion": 4 + }, + { + "commandClassName": "Multilevel Switch", + "commandClass": 38, + "endpoint": 0, + "property": "Up", + "propertyName": "Up", + "metadata": { + "type": "boolean", + "readable": true, + "writeable": true, + "label": "Perform a level change (Up)", + "ccSpecific": { + "switchType": 2 + } + }, + "ccVersion": 4 + }, + { + "commandClassName": "Multilevel Switch", + "commandClass": 38, + "endpoint": 0, + "property": "Down", + "propertyName": "Down", + "metadata": { + "type": "boolean", + "readable": true, + "writeable": true, + "label": "Perform a level change (Down)", + "ccSpecific": { + "switchType": 2 + } + }, + "ccVersion": 4 + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "sceneId", + "propertyName": "sceneId", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 1, + "max": 255, + "label": "Scene ID" + }, + "ccVersion": 0 + }, + { + "commandClassName": "Scene Activation", + "commandClass": 43, + "endpoint": 0, + "property": "dimmingDuration", + "propertyName": "dimmingDuration", + "metadata": { + "type": "any", + "readable": true, + "writeable": true, + "label": "Dimming duration" + }, + "ccVersion": 0 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 1, + "propertyName": "Delayed OFF time", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 255, + "default": 0, + "format": 1, + "allowManualEntry": true, + "label": "Delayed OFF time", + "description": "Time in seconds to delay OFF", + "isFromConfig": true + }, + "value": 10, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 2, + "propertyName": "Panic ON time", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 255, + "default": 0, + "format": 1, + "allowManualEntry": true, + "label": "Panic ON time", + "description": "Time in seconds for panic mode ON", + "isFromConfig": true + }, + "value": 1, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 3, + "propertyName": "Panic OFF time", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 255, + "default": 0, + "format": 1, + "allowManualEntry": true, + "label": "Panic OFF time", + "description": "time in seconds for OFF in panic mode", + "isFromConfig": true + }, + "value": 1, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 5, + "propertyName": "Power Up State", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 1, + "max": 3, + "default": 1, + "format": 0, + "allowManualEntry": false, + "states": { + "1": "OFF", + "2": "ON", + "3": "Last State" + }, + "label": "Power Up State", + "description": "Power Up State of the switch", + "isFromConfig": true + }, + "value": 1, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 6, + "propertyName": "Panic mode enable", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "OFF", + "1": "ON" + }, + "label": "Panic mode enable", + "description": "Enables this switch to participate in panic mode", + "isFromConfig": true + }, + "value": 0, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 7, + "propertyName": "Dimmer Ramp Time", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 255, + "default": 1, + "format": 1, + "allowManualEntry": true, + "label": "Dimmer Ramp Time", + "description": "Time in seconds to reach desired level", + "isFromConfig": true + }, + "value": 3, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 8, + "propertyName": "Kickstart / Rapid Start", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 1, + "default": 0, + "format": 0, + "allowManualEntry": false, + "states": { + "0": "disables", + "1": "enables" + }, + "label": "Kickstart / Rapid Start", + "description": "Ensures that LED / CFL bulbs turn on when the preset dim level is low", + "isFromConfig": true + }, + "value": 0, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 9, + "propertyName": "Reset max/min levels to factory default", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 0, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Reset max/min levels to factory default", + "description": "Reset max/min levels to factory default", + "isFromConfig": true + }, + "value": 1, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 12, + "propertyName": "Maximum Dimming Level", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 99, + "default": 99, + "format": 0, + "allowManualEntry": true, + "label": "Maximum Dimming Level", + "isFromConfig": true + }, + "value": 99, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 13, + "propertyName": "Blue LED brightness level while dimmer is ON", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 4, + "default": 4, + "format": 0, + "allowManualEntry": true, + "label": "Blue LED brightness level while dimmer is ON", + "isFromConfig": true + }, + "value": 3, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 14, + "propertyName": "Blue LED brightness level while dimmer is OFF", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 4, + "default": 1, + "format": 0, + "allowManualEntry": true, + "label": "Blue LED brightness level while dimmer is OFF", + "isFromConfig": true + }, + "value": 2, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 15, + "propertyName": "Amber LED brightness level while the dimmer is ON", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 4, + "default": 0, + "format": 0, + "allowManualEntry": true, + "label": "Amber LED brightness level while the dimmer is ON", + "isFromConfig": true + }, + "value": 3, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 16, + "propertyName": "Amber LED brightness level while the dimmer is OFF", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 0, + "max": 4, + "default": 2, + "format": 0, + "allowManualEntry": true, + "label": "Amber LED brightness level while the dimmer is OFF", + "isFromConfig": true + }, + "value": 0, + "ccVersion": 1 + }, + { + "commandClassName": "Configuration", + "commandClass": 112, + "endpoint": 0, + "property": 11, + "propertyName": "Minimum Dimming Level", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "valueSize": 1, + "min": 1, + "max": 99, + "default": 1, + "format": 0, + "allowManualEntry": true, + "label": "Minimum Dimming Level", + "isFromConfig": true + }, + "value": 20, + "ccVersion": 1 + }, + { + "commandClassName": "Manufacturer Specific", + "commandClass": 114, + "endpoint": 0, + "property": "manufacturerId", + "propertyName": "manufacturerId", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 65535, + "label": "Manufacturer ID" + }, + "value": 26, + "ccVersion": 2 + }, + { + "commandClassName": "Manufacturer Specific", + "commandClass": 114, + "endpoint": 0, + "property": "productType", + "propertyName": "productType", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 65535, + "label": "Product type" + }, + "value": 17481, + "ccVersion": 2 + }, + { + "commandClassName": "Manufacturer Specific", + "commandClass": 114, + "endpoint": 0, + "property": "productId", + "propertyName": "productId", + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 65535, + "label": "Product ID" + }, + "value": 1281, + "ccVersion": 2 + }, + { + "commandClassName": "Protection", + "commandClass": 117, + "endpoint": 0, + "property": "local", + "propertyName": "local", + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "label": "Local protection state", + "states": { + "0": "Unprotected", + "1": "ProtectedBySequence", + "2": "NoOperationPossible" + } + }, + "value": 0, + "ccVersion": 1 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "libraryType", + "propertyName": "libraryType", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Library type" + }, + "value": 3, + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "protocolVersion", + "propertyName": "protocolVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol version" + }, + "value": "5.3", + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "firmwareVersions", + "propertyName": "firmwareVersions", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip firmware versions" + }, + "value": [ + "1.0" + ], + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "hardwareVersion", + "propertyName": "hardwareVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip hardware version" + }, + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "sdkVersion", + "propertyName": "sdkVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": "6.71.3", + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "applicationFrameworkAPIVersion", + "propertyName": "applicationFrameworkAPIVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": "3.1.1", + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "applicationFrameworkBuildNumber", + "propertyName": "applicationFrameworkBuildNumber", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": 52445, + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "hostInterfaceVersion", + "propertyName": "hostInterfaceVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": "unused", + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "hostInterfaceBuildNumber", + "propertyName": "hostInterfaceBuildNumber", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": 0, + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "zWaveProtocolVersion", + "propertyName": "zWaveProtocolVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": "5.3.0", + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "zWaveProtocolBuildNumber", + "propertyName": "zWaveProtocolBuildNumber", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": 43, + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "applicationVersion", + "propertyName": "applicationVersion", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": "unused", + "ccVersion": 3 + }, + { + "commandClassName": "Version", + "commandClass": 134, + "endpoint": 0, + "property": "applicationBuildNumber", + "propertyName": "applicationBuildNumber", + "metadata": { + "type": "any", + "readable": true, + "writeable": true + }, + "value": 0, + "ccVersion": 3 + } + ] +} \ No newline at end of file