diff --git a/tests/components/deconz/test_climate.py b/tests/components/deconz/test_climate.py index 5577a2d0414..92ca38fdf4d 100644 --- a/tests/components/deconz/test_climate.py +++ b/tests/components/deconz/test_climate.py @@ -1,6 +1,6 @@ """deCONZ climate platform tests.""" -from copy import deepcopy +from unittest.mock import patch import pytest @@ -27,14 +27,18 @@ from homeassistant.components.climate.const import ( HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_OFF, + PRESET_BOOST, PRESET_COMFORT, + PRESET_ECO, ) from homeassistant.components.deconz.climate import ( DECONZ_FAN_SMART, + DECONZ_PRESET_AUTO, + DECONZ_PRESET_COMPLEX, + DECONZ_PRESET_HOLIDAY, DECONZ_PRESET_MANUAL, ) from homeassistant.components.deconz.const import CONF_ALLOW_CLIP_SENSOR -from homeassistant.components.deconz.gateway import get_gateway_from_config_entry from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_TEMPERATURE, @@ -48,31 +52,6 @@ from .test_gateway import ( setup_deconz_integration, ) -SENSORS = { - "1": { - "id": "Thermostat id", - "name": "Thermostat", - "type": "ZHAThermostat", - "state": {"on": True, "temperature": 2260, "valve": 30}, - "config": { - "battery": 100, - "heatsetpoint": 2200, - "mode": "auto", - "offset": 10, - "reachable": True, - }, - "uniqueid": "00:00:00:00:00:00:00:00-00", - }, - "2": { - "id": "CLIP thermostat id", - "name": "CLIP thermostat", - "type": "CLIPThermostat", - "state": {"on": True, "temperature": 2260, "valve": 30}, - "config": {"reachable": True}, - "uniqueid": "00:00:00:00:00:00:00:02-00", - }, -} - async def test_no_sensors(hass, aioclient_mock): """Test that no sensors in deconz results in no climate entities.""" @@ -80,48 +59,47 @@ async def test_no_sensors(hass, aioclient_mock): assert len(hass.states.async_all()) == 0 -async def test_simple_climate_device(hass, aioclient_mock): +async def test_simple_climate_device(hass, aioclient_mock, mock_deconz_websocket): """Test successful creation of climate entities. This is a simple water heater that only supports setting temperature and on and off. """ - data = deepcopy(DECONZ_WEB_REQUEST) - data["sensors"] = { - "0": { - "config": { - "battery": 59, - "displayflipped": None, - "heatsetpoint": 2100, - "locked": True, - "mountingmode": None, - "offset": 0, - "on": True, - "reachable": True, - }, - "ep": 1, - "etag": "6130553ac247174809bae47144ee23f8", - "lastseen": "2020-11-29T19:31Z", - "manufacturername": "Danfoss", - "modelid": "eTRV0100", - "name": "thermostat", - "state": { - "errorcode": None, - "lastupdated": "2020-11-29T19:28:40.665", - "mountingmodeactive": False, - "on": True, - "temperature": 2102, - "valve": 24, - "windowopen": "Closed", - }, - "swversion": "01.02.0008 01.02", - "type": "ZHAThermostat", - "uniqueid": "14:b4:57:ff:fe:d5:4e:77-01-0201", + data = { + "sensors": { + "0": { + "config": { + "battery": 59, + "displayflipped": None, + "heatsetpoint": 2100, + "locked": True, + "mountingmode": None, + "offset": 0, + "on": True, + "reachable": True, + }, + "ep": 1, + "etag": "6130553ac247174809bae47144ee23f8", + "lastseen": "2020-11-29T19:31Z", + "manufacturername": "Danfoss", + "modelid": "eTRV0100", + "name": "thermostat", + "state": { + "errorcode": None, + "lastupdated": "2020-11-29T19:28:40.665", + "mountingmodeactive": False, + "on": True, + "temperature": 2102, + "valve": 24, + "windowopen": "Closed", + }, + "swversion": "01.02.0008 01.02", + "type": "ZHAThermostat", + "uniqueid": "14:b4:57:ff:fe:d5:4e:77-01-0201", + } } } - config_entry = await setup_deconz_integration( - hass, aioclient_mock, get_state_response=data - ) - gateway = get_gateway_from_config_entry(hass, config_entry) + with patch.dict(DECONZ_WEB_REQUEST, data): + config_entry = await setup_deconz_integration(hass, aioclient_mock) assert len(hass.states.async_all()) == 2 climate_thermostat = hass.states.get("climate.thermostat") @@ -137,28 +115,28 @@ async def test_simple_climate_device(hass, aioclient_mock): # Event signals thermostat configured off - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "0", "state": {"on": False}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.thermostat").state == STATE_OFF # Event signals thermostat state on - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "0", "state": {"on": True}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.thermostat").state == HVAC_MODE_HEAT @@ -198,14 +176,29 @@ async def test_simple_climate_device(hass, aioclient_mock): ) -async def test_climate_device_without_cooling_support(hass, aioclient_mock): +async def test_climate_device_without_cooling_support( + hass, aioclient_mock, mock_deconz_websocket +): """Test successful creation of sensor entities.""" - data = deepcopy(DECONZ_WEB_REQUEST) - data["sensors"] = deepcopy(SENSORS) - config_entry = await setup_deconz_integration( - hass, aioclient_mock, get_state_response=data - ) - gateway = get_gateway_from_config_entry(hass, config_entry) + data = { + "sensors": { + "1": { + "name": "Thermostat", + "type": "ZHAThermostat", + "state": {"on": True, "temperature": 2260, "valve": 30}, + "config": { + "battery": 100, + "heatsetpoint": 2200, + "mode": "auto", + "offset": 10, + "reachable": True, + }, + "uniqueid": "00:00:00:00:00:00:00:00-00", + } + } + } + with patch.dict(DECONZ_WEB_REQUEST, data): + config_entry = await setup_deconz_integration(hass, aioclient_mock) assert len(hass.states.async_all()) == 2 climate_thermostat = hass.states.get("climate.thermostat") @@ -224,21 +217,21 @@ async def test_climate_device_without_cooling_support(hass, aioclient_mock): # Event signals thermostat configured off - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "1", "config": {"mode": "off"}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.thermostat").state == STATE_OFF # Event signals thermostat state on - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", @@ -246,21 +239,21 @@ async def test_climate_device_without_cooling_support(hass, aioclient_mock): "config": {"mode": "other"}, "state": {"on": True}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.thermostat").state == HVAC_MODE_HEAT # Event signals thermostat state off - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "1", "state": {"on": False}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.thermostat").state == STATE_OFF @@ -336,7 +329,7 @@ async def test_climate_device_without_cooling_support(hass, aioclient_mock): await hass.config_entries.async_unload(config_entry.entry_id) states = hass.states.async_all() - assert len(hass.states.async_all()) == 2 + assert len(states) == 2 for state in states: assert state.state == STATE_UNAVAILABLE @@ -345,40 +338,41 @@ async def test_climate_device_without_cooling_support(hass, aioclient_mock): assert len(hass.states.async_all()) == 0 -async def test_climate_device_with_cooling_support(hass, aioclient_mock): +async def test_climate_device_with_cooling_support( + hass, aioclient_mock, mock_deconz_websocket +): """Test successful creation of sensor entities.""" - data = deepcopy(DECONZ_WEB_REQUEST) - data["sensors"] = { - "0": { - "config": { - "battery": 25, - "coolsetpoint": None, - "fanmode": None, - "heatsetpoint": 2222, - "mode": "heat", - "offset": 0, - "on": True, - "reachable": True, - }, - "ep": 1, - "etag": "074549903686a77a12ef0f06c499b1ef", - "lastseen": "2020-11-27T13:45Z", - "manufacturername": "Zen Within", - "modelid": "Zen-01", - "name": "Zen-01", - "state": { - "lastupdated": "2020-11-27T13:42:40.863", - "on": False, - "temperature": 2320, - }, - "type": "ZHAThermostat", - "uniqueid": "00:24:46:00:00:11:6f:56-01-0201", + data = { + "sensors": { + "0": { + "config": { + "battery": 25, + "coolsetpoint": None, + "fanmode": None, + "heatsetpoint": 2222, + "mode": "heat", + "offset": 0, + "on": True, + "reachable": True, + }, + "ep": 1, + "etag": "074549903686a77a12ef0f06c499b1ef", + "lastseen": "2020-11-27T13:45Z", + "manufacturername": "Zen Within", + "modelid": "Zen-01", + "name": "Zen-01", + "state": { + "lastupdated": "2020-11-27T13:42:40.863", + "on": False, + "temperature": 2320, + }, + "type": "ZHAThermostat", + "uniqueid": "00:24:46:00:00:11:6f:56-01-0201", + } } } - config_entry = await setup_deconz_integration( - hass, aioclient_mock, get_state_response=data - ) - gateway = get_gateway_from_config_entry(hass, config_entry) + with patch.dict(DECONZ_WEB_REQUEST, data): + config_entry = await setup_deconz_integration(hass, aioclient_mock) assert len(hass.states.async_all()) == 2 climate_thermostat = hass.states.get("climate.zen_01") @@ -395,14 +389,14 @@ async def test_climate_device_with_cooling_support(hass, aioclient_mock): # Event signals thermostat state cool - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "0", "config": {"mode": "cool"}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.zen_01").state == HVAC_MODE_COOL @@ -422,40 +416,41 @@ async def test_climate_device_with_cooling_support(hass, aioclient_mock): assert aioclient_mock.mock_calls[1][2] == {"coolsetpoint": 2000.0} -async def test_climate_device_with_fan_support(hass, aioclient_mock): +async def test_climate_device_with_fan_support( + hass, aioclient_mock, mock_deconz_websocket +): """Test successful creation of sensor entities.""" - data = deepcopy(DECONZ_WEB_REQUEST) - data["sensors"] = { - "0": { - "config": { - "battery": 25, - "coolsetpoint": None, - "fanmode": "auto", - "heatsetpoint": 2222, - "mode": "heat", - "offset": 0, - "on": True, - "reachable": True, - }, - "ep": 1, - "etag": "074549903686a77a12ef0f06c499b1ef", - "lastseen": "2020-11-27T13:45Z", - "manufacturername": "Zen Within", - "modelid": "Zen-01", - "name": "Zen-01", - "state": { - "lastupdated": "2020-11-27T13:42:40.863", - "on": False, - "temperature": 2320, - }, - "type": "ZHAThermostat", - "uniqueid": "00:24:46:00:00:11:6f:56-01-0201", + data = { + "sensors": { + "0": { + "config": { + "battery": 25, + "coolsetpoint": None, + "fanmode": "auto", + "heatsetpoint": 2222, + "mode": "heat", + "offset": 0, + "on": True, + "reachable": True, + }, + "ep": 1, + "etag": "074549903686a77a12ef0f06c499b1ef", + "lastseen": "2020-11-27T13:45Z", + "manufacturername": "Zen Within", + "modelid": "Zen-01", + "name": "Zen-01", + "state": { + "lastupdated": "2020-11-27T13:42:40.863", + "on": False, + "temperature": 2320, + }, + "type": "ZHAThermostat", + "uniqueid": "00:24:46:00:00:11:6f:56-01-0201", + } } } - config_entry = await setup_deconz_integration( - hass, aioclient_mock, get_state_response=data - ) - gateway = get_gateway_from_config_entry(hass, config_entry) + with patch.dict(DECONZ_WEB_REQUEST, data): + config_entry = await setup_deconz_integration(hass, aioclient_mock) assert len(hass.states.async_all()) == 2 climate_thermostat = hass.states.get("climate.zen_01") @@ -473,21 +468,21 @@ async def test_climate_device_with_fan_support(hass, aioclient_mock): # Event signals fan mode defaults to off - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "0", "config": {"fanmode": "unsupported"}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.zen_01").attributes["fan_mode"] == FAN_OFF # Event signals unsupported fan mode - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", @@ -495,21 +490,21 @@ async def test_climate_device_with_fan_support(hass, aioclient_mock): "config": {"fanmode": "unsupported"}, "state": {"on": True}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.zen_01").attributes["fan_mode"] == FAN_ON # Event signals unsupported fan mode - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "0", "config": {"fanmode": "unsupported"}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.zen_01").attributes["fan_mode"] == FAN_ON @@ -549,41 +544,40 @@ async def test_climate_device_with_fan_support(hass, aioclient_mock): ) -async def test_climate_device_with_preset(hass, aioclient_mock): +async def test_climate_device_with_preset(hass, aioclient_mock, mock_deconz_websocket): """Test successful creation of sensor entities.""" - data = deepcopy(DECONZ_WEB_REQUEST) - data["sensors"] = { - "0": { - "config": { - "battery": 25, - "coolsetpoint": None, - "fanmode": None, - "heatsetpoint": 2222, - "mode": "heat", - "preset": "auto", - "offset": 0, - "on": True, - "reachable": True, - }, - "ep": 1, - "etag": "074549903686a77a12ef0f06c499b1ef", - "lastseen": "2020-11-27T13:45Z", - "manufacturername": "Zen Within", - "modelid": "Zen-01", - "name": "Zen-01", - "state": { - "lastupdated": "2020-11-27T13:42:40.863", - "on": False, - "temperature": 2320, - }, - "type": "ZHAThermostat", - "uniqueid": "00:24:46:00:00:11:6f:56-01-0201", + data = { + "sensors": { + "0": { + "config": { + "battery": 25, + "coolsetpoint": None, + "fanmode": None, + "heatsetpoint": 2222, + "mode": "heat", + "preset": "auto", + "offset": 0, + "on": True, + "reachable": True, + }, + "ep": 1, + "etag": "074549903686a77a12ef0f06c499b1ef", + "lastseen": "2020-11-27T13:45Z", + "manufacturername": "Zen Within", + "modelid": "Zen-01", + "name": "Zen-01", + "state": { + "lastupdated": "2020-11-27T13:42:40.863", + "on": False, + "temperature": 2320, + }, + "type": "ZHAThermostat", + "uniqueid": "00:24:46:00:00:11:6f:56-01-0201", + } } } - config_entry = await setup_deconz_integration( - hass, aioclient_mock, get_state_response=data - ) - gateway = get_gateway_from_config_entry(hass, config_entry) + with patch.dict(DECONZ_WEB_REQUEST, data): + config_entry = await setup_deconz_integration(hass, aioclient_mock) assert len(hass.states.async_all()) == 2 @@ -591,27 +585,27 @@ async def test_climate_device_with_preset(hass, aioclient_mock): assert climate_zen_01.state == HVAC_MODE_HEAT assert climate_zen_01.attributes["current_temperature"] == 23.2 assert climate_zen_01.attributes["temperature"] == 22.2 - assert climate_zen_01.attributes["preset_mode"] == "auto" + assert climate_zen_01.attributes["preset_mode"] == DECONZ_PRESET_AUTO assert climate_zen_01.attributes["preset_modes"] == [ - "auto", - "boost", - "comfort", - "complex", - "eco", - "holiday", - "manual", + DECONZ_PRESET_AUTO, + PRESET_BOOST, + PRESET_COMFORT, + DECONZ_PRESET_COMPLEX, + PRESET_ECO, + DECONZ_PRESET_HOLIDAY, + DECONZ_PRESET_MANUAL, ] # Event signals deCONZ preset - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "0", "config": {"preset": "manual"}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert ( @@ -621,14 +615,14 @@ async def test_climate_device_with_preset(hass, aioclient_mock): # Event signals unknown preset - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "0", "config": {"preset": "unsupported"}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.zen_01").attributes["preset_mode"] is None @@ -670,19 +664,36 @@ async def test_climate_device_with_preset(hass, aioclient_mock): async def test_clip_climate_device(hass, aioclient_mock): """Test successful creation of sensor entities.""" - data = deepcopy(DECONZ_WEB_REQUEST) - data["sensors"] = deepcopy(SENSORS) - config_entry = await setup_deconz_integration( - hass, - aioclient_mock, - options={CONF_ALLOW_CLIP_SENSOR: True}, - get_state_response=data, - ) + data = { + "sensors": { + "1": { + "name": "Thermostat", + "type": "ZHAThermostat", + "state": {"on": True, "temperature": 2260, "valve": 30}, + "config": { + "battery": 100, + "heatsetpoint": 2200, + "mode": "auto", + "offset": 10, + "reachable": True, + }, + "uniqueid": "00:00:00:00:00:00:00:00-00", + }, + "2": { + "name": "CLIP thermostat", + "type": "CLIPThermostat", + "state": {"on": True, "temperature": 2260, "valve": 30}, + "config": {"reachable": True}, + "uniqueid": "00:00:00:00:00:00:00:02-00", + }, + } + } + with patch.dict(DECONZ_WEB_REQUEST, data): + config_entry = await setup_deconz_integration( + hass, aioclient_mock, options={CONF_ALLOW_CLIP_SENSOR: True} + ) assert len(hass.states.async_all()) == 3 - assert hass.states.get("climate.thermostat").state == HVAC_MODE_AUTO - assert hass.states.get("sensor.thermostat") is None - assert hass.states.get("sensor.thermostat_battery_level").state == "100" assert hass.states.get("climate.clip_thermostat").state == HVAC_MODE_HEAT # Disallow clip sensors @@ -693,7 +704,7 @@ async def test_clip_climate_device(hass, aioclient_mock): await hass.async_block_till_done() assert len(hass.states.async_all()) == 2 - assert hass.states.get("climate.clip_thermostat") is None + assert not hass.states.get("climate.clip_thermostat") # Allow clip sensors @@ -706,45 +717,70 @@ async def test_clip_climate_device(hass, aioclient_mock): assert hass.states.get("climate.clip_thermostat").state == HVAC_MODE_HEAT -async def test_verify_state_update(hass, aioclient_mock): +async def test_verify_state_update(hass, aioclient_mock, mock_deconz_websocket): """Test that state update properly.""" - data = deepcopy(DECONZ_WEB_REQUEST) - data["sensors"] = deepcopy(SENSORS) - config_entry = await setup_deconz_integration( - hass, aioclient_mock, get_state_response=data - ) - gateway = get_gateway_from_config_entry(hass, config_entry) + data = { + "sensors": { + "1": { + "name": "Thermostat", + "type": "ZHAThermostat", + "state": {"on": True, "temperature": 2260, "valve": 30}, + "config": { + "battery": 100, + "heatsetpoint": 2200, + "mode": "auto", + "offset": 10, + "reachable": True, + }, + "uniqueid": "00:00:00:00:00:00:00:00-00", + } + } + } + with patch.dict(DECONZ_WEB_REQUEST, data): + await setup_deconz_integration(hass, aioclient_mock) assert hass.states.get("climate.thermostat").state == HVAC_MODE_AUTO - state_changed_event = { + event_changed_sensor = { "t": "event", "e": "changed", "r": "sensors", "id": "1", "state": {"on": False}, } - gateway.api.event_handler(state_changed_event) + await mock_deconz_websocket(data=event_changed_sensor) await hass.async_block_till_done() assert hass.states.get("climate.thermostat").state == HVAC_MODE_AUTO - assert gateway.api.sensors["1"].changed_keys == {"state", "r", "t", "on", "e", "id"} -async def test_add_new_climate_device(hass, aioclient_mock): +async def test_add_new_climate_device(hass, aioclient_mock, mock_deconz_websocket): """Test that adding a new climate device works.""" - config_entry = await setup_deconz_integration(hass, aioclient_mock) - gateway = get_gateway_from_config_entry(hass, config_entry) - assert len(hass.states.async_all()) == 0 - - state_added_event = { + event_added_sensor = { "t": "event", "e": "added", "r": "sensors", "id": "1", - "sensor": deepcopy(SENSORS["1"]), + "sensor": { + "id": "Thermostat id", + "name": "Thermostat", + "type": "ZHAThermostat", + "state": {"on": True, "temperature": 2260, "valve": 30}, + "config": { + "battery": 100, + "heatsetpoint": 2200, + "mode": "auto", + "offset": 10, + "reachable": True, + }, + "uniqueid": "00:00:00:00:00:00:00:00-00", + }, } - gateway.api.event_handler(state_added_event) + + await setup_deconz_integration(hass, aioclient_mock) + assert len(hass.states.async_all()) == 0 + + await mock_deconz_websocket(data=event_added_sensor) await hass.async_block_till_done() assert len(hass.states.async_all()) == 2