diff --git a/homeassistant/components/zwave_js/climate.py b/homeassistant/components/zwave_js/climate.py index 54966538aae..cc449b89e91 100644 --- a/homeassistant/components/zwave_js/climate.py +++ b/homeassistant/components/zwave_js/climate.py @@ -118,7 +118,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity): super().__init__(config_entry, client, info) self._hvac_modes: Dict[str, Optional[int]] = {} self._hvac_presets: Dict[str, Optional[int]] = {} - self._unit_value: ZwaveValue = None + self._unit_value: Optional[ZwaveValue] = None self._current_mode = self.get_zwave_value( THERMOSTAT_MODE_PROPERTY, command_class=CommandClass.THERMOSTAT_MODE @@ -215,7 +215,11 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity): @property def temperature_unit(self) -> str: """Return the unit of measurement used by the platform.""" - if "f" in self._unit_value.metadata.unit.lower(): + if ( + self._unit_value + and self._unit_value.metadata.unit + and "f" in self._unit_value.metadata.unit.lower() + ): return TEMP_FAHRENHEIT return TEMP_CELSIUS diff --git a/tests/components/zwave_js/common.py b/tests/components/zwave_js/common.py index a5ee628754e..ec54e139404 100644 --- a/tests/components/zwave_js/common.py +++ b/tests/components/zwave_js/common.py @@ -16,6 +16,7 @@ PROPERTY_DOOR_STATUS_BINARY_SENSOR = ( CLIMATE_RADIO_THERMOSTAT_ENTITY = "climate.z_wave_thermostat" CLIMATE_DANFOSS_LC13_ENTITY = "climate.living_connect_z_thermostat" CLIMATE_FLOOR_THERMOSTAT_ENTITY = "climate.floor_thermostat" +CLIMATE_MAIN_HEAT_ACTIONNER = "climate.main_heat_actionner" BULB_6_MULTI_COLOR_LIGHT_ENTITY = "light.bulb_6_multi_color" EATON_RF9640_ENTITY = "light.allloaddimmer" AEON_SMART_SWITCH_LIGHT_ENTITY = "light.smart_switch_6" diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index af87d9d49e1..b171fb38425 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -240,6 +240,12 @@ def nortek_thermostat_state_fixture(): return json.loads(load_fixture("zwave_js/nortek_thermostat_state.json")) +@pytest.fixture(name="srt321_hrt4_zw_state", scope="session") +def srt321_hrt4_zw_state_fixture(): + """Load the climate HRT4-ZW / SRT321 / SRT322 thermostat node state fixture data.""" + return json.loads(load_fixture("zwave_js/srt321_hrt4_zw_state.json")) + + @pytest.fixture(name="chain_actuator_zws12_state", scope="session") def window_cover_state_fixture(): """Load the window cover node state fixture data.""" @@ -423,6 +429,14 @@ def nortek_thermostat_fixture(client, nortek_thermostat_state): return node +@pytest.fixture(name="srt321_hrt4_zw") +def srt321_hrt4_zw_fixture(client, srt321_hrt4_zw_state): + """Mock a HRT4-ZW / SRT321 / SRT322 thermostat node.""" + node = Node(client, copy.deepcopy(srt321_hrt4_zw_state)) + client.driver.controller.nodes[node.node_id] = node + return node + + @pytest.fixture(name="aeotec_radiator_thermostat") def aeotec_radiator_thermostat_fixture(client, aeotec_radiator_thermostat_state): """Mock a Aeotec thermostat node.""" diff --git a/tests/components/zwave_js/test_climate.py b/tests/components/zwave_js/test_climate.py index 44804825885..ea75f10328c 100644 --- a/tests/components/zwave_js/test_climate.py +++ b/tests/components/zwave_js/test_climate.py @@ -31,6 +31,7 @@ from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE from .common import ( CLIMATE_DANFOSS_LC13_ENTITY, CLIMATE_FLOOR_THERMOSTAT_ENTITY, + CLIMATE_MAIN_HEAT_ACTIONNER, CLIMATE_RADIO_THERMOSTAT_ENTITY, ) @@ -488,3 +489,19 @@ async def test_thermostat_heatit(hass, client, climate_heatit_z_trm3, integratio assert state.attributes[ATTR_TEMPERATURE] == 22.5 assert state.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_IDLE assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE + + +async def test_thermostat_srt321_hrt4_zw(hass, client, srt321_hrt4_zw, integration): + """Test a climate entity from a HRT4-ZW / SRT321 thermostat device. + + This device currently has no setpoint values. + """ + state = hass.states.get(CLIMATE_MAIN_HEAT_ACTIONNER) + + assert state + assert state.state == HVAC_MODE_OFF + assert state.attributes[ATTR_HVAC_MODES] == [ + HVAC_MODE_OFF, + HVAC_MODE_HEAT, + ] + assert state.attributes[ATTR_CURRENT_TEMPERATURE] is None diff --git a/tests/fixtures/zwave_js/srt321_hrt4_zw_state.json b/tests/fixtures/zwave_js/srt321_hrt4_zw_state.json new file mode 100644 index 00000000000..a2fdaa99561 --- /dev/null +++ b/tests/fixtures/zwave_js/srt321_hrt4_zw_state.json @@ -0,0 +1,262 @@ +{ + "nodeId": 20, + "index": 0, + "status": 4, + "ready": true, + "deviceClass": { + "basic": { + "key": 4, + "label": "Routing Slave" + }, + "generic": { + "key": 8, + "label": "Thermostat" + }, + "specific": { + "key": 0, + "label": "Unused" + }, + "mandatorySupportedCCs": [], + "mandatoryControlledCCs": [] + }, + "isListening": true, + "isFrequentListening": false, + "isRouting": true, + "maxBaudRate": 40000, + "isSecure": false, + "version": 3, + "isBeaming": true, + "manufacturerId": 89, + "productId": 1, + "productType": 3, + "firmwareVersion": "2.0", + "name": "main_heat_actionner", + "location": "kitchen", + "deviceConfig": { + "filename": "/opt/node_modules/@zwave-js/config/config/devices/0x0059/asr-zw.json", + "manufacturerId": 89, + "manufacturer": "Secure Meters (UK) Ltd.", + "label": "SRT322", + "description": "Thermostat Receiver", + "devices": [ + { + "productType": "0x0003", + "productId": "0x0001" + } + ], + "firmwareVersion": { + "min": "0.0", + "max": "255.255" + } + }, + "label": "SRT322", + "neighbors": [ + 1, + 5, + 10, + 12, + 13, + 14, + 15, + 18, + 21 + ], + "interviewAttempts": 1, + "interviewStage": 7, + "commandClasses": [ + { + "id": 37, + "name": "Binary Switch", + "version": 1, + "isSecure": false + }, + { + "id": 64, + "name": "Thermostat Mode", + "version": 1, + "isSecure": false + }, + { + "id": 114, + "name": "Manufacturer Specific", + "version": 1, + "isSecure": false + }, + { + "id": 134, + "name": "Version", + "version": 1, + "isSecure": false + } + ], + "endpoints": [ + { + "nodeId": 20, + "index": 0 + } + ], + "values": [ + { + "endpoint": 0, + "commandClass": 37, + "commandClassName": "Binary Switch", + "property": "currentValue", + "propertyName": "currentValue", + "ccVersion": 1, + "metadata": { + "type": "boolean", + "readable": true, + "writeable": false, + "label": "Current value" + }, + "value": false + }, + { + "endpoint": 0, + "commandClass": 37, + "commandClassName": "Binary Switch", + "property": "targetValue", + "propertyName": "targetValue", + "ccVersion": 1, + "metadata": { + "type": "boolean", + "readable": true, + "writeable": true, + "label": "Target value" + }, + "value": false + }, + { + "endpoint": 0, + "commandClass": 64, + "commandClassName": "Thermostat Mode", + "property": "mode", + "propertyName": "mode", + "ccVersion": 1, + "metadata": { + "type": "number", + "readable": true, + "writeable": true, + "min": 0, + "max": 255, + "states": { + "0": "Off", + "1": "Heat" + }, + "label": "Thermostat mode" + }, + "value": 0 + }, + { + "endpoint": 0, + "commandClass": 64, + "commandClassName": "Thermostat Mode", + "property": "manufacturerData", + "propertyName": "manufacturerData", + "ccVersion": 1, + "metadata": { + "type": "any", + "readable": true, + "writeable": true + } + }, + { + "endpoint": 0, + "commandClass": 114, + "commandClassName": "Manufacturer Specific", + "property": "manufacturerId", + "propertyName": "manufacturerId", + "ccVersion": 1, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 65535, + "label": "Manufacturer ID" + }, + "value": 89 + }, + { + "endpoint": 0, + "commandClass": 114, + "commandClassName": "Manufacturer Specific", + "property": "productType", + "propertyName": "productType", + "ccVersion": 1, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 65535, + "label": "Product type" + }, + "value": 3 + }, + { + "endpoint": 0, + "commandClass": 114, + "commandClassName": "Manufacturer Specific", + "property": "productId", + "propertyName": "productId", + "ccVersion": 1, + "metadata": { + "type": "number", + "readable": true, + "writeable": false, + "min": 0, + "max": 65535, + "label": "Product ID" + }, + "value": 1 + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "libraryType", + "propertyName": "libraryType", + "ccVersion": 1, + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Library type" + }, + "value": 6 + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "protocolVersion", + "propertyName": "protocolVersion", + "ccVersion": 1, + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave protocol version" + }, + "value": "2.78" + }, + { + "endpoint": 0, + "commandClass": 134, + "commandClassName": "Version", + "property": "firmwareVersions", + "propertyName": "firmwareVersions", + "ccVersion": 1, + "metadata": { + "type": "any", + "readable": true, + "writeable": false, + "label": "Z-Wave chip firmware versions" + }, + "value": [ + "2.0" + ] + } + ] + }