From 1faef0a4d429e8c636beed2728ad564f379f650c Mon Sep 17 00:00:00 2001
From: Robert Svensson <Kane610@users.noreply.github.com>
Date: Tue, 1 Dec 2020 18:49:58 +0100
Subject: [PATCH] Make simple deCONZ thermostats work (#43781)

---
 homeassistant/components/deconz/climate.py |   9 +-
 tests/components/deconz/test_climate.py    | 121 +++++++++++++++++++++
 2 files changed, 129 insertions(+), 1 deletion(-)

diff --git a/homeassistant/components/deconz/climate.py b/homeassistant/components/deconz/climate.py
index afa9e8dcd9f..0c1fe2da1e3 100644
--- a/homeassistant/components/deconz/climate.py
+++ b/homeassistant/components/deconz/climate.py
@@ -72,7 +72,12 @@ class DeconzThermostat(DeconzDevice, ClimateEntity):
         super().__init__(device, gateway)
 
         self._hvac_modes = dict(HVAC_MODES)
-        if "coolsetpoint" not in device.raw["config"]:
+        if "mode" not in device.raw["config"]:
+            self._hvac_modes = {
+                HVAC_MODE_HEAT: True,
+                HVAC_MODE_OFF: False,
+            }
+        elif "coolsetpoint" not in device.raw["config"]:
             self._hvac_modes.pop(HVAC_MODE_COOL)
 
         self._features = SUPPORT_TARGET_TEMPERATURE
@@ -110,6 +115,8 @@ class DeconzThermostat(DeconzDevice, ClimateEntity):
             raise ValueError(f"Unsupported HVAC mode {hvac_mode}")
 
         data = {"mode": self._hvac_modes[hvac_mode]}
+        if len(self._hvac_modes) == 2:  # Only allow turn on and off thermostat
+            data = {"on": self._hvac_modes[hvac_mode]}
 
         await self._device.async_set_config(data)
 
diff --git a/tests/components/deconz/test_climate.py b/tests/components/deconz/test_climate.py
index 751f1572239..cea660b855b 100644
--- a/tests/components/deconz/test_climate.py
+++ b/tests/components/deconz/test_climate.py
@@ -73,6 +73,127 @@ async def test_no_sensors(hass):
     assert len(hass.states.async_all()) == 0
 
 
+async def test_simple_climate_device(hass):
+    """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": None,
+                "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, get_state_response=data)
+    gateway = get_gateway_from_config_entry(hass, config_entry)
+
+    assert len(hass.states.async_all()) == 2
+    climate_thermostat = hass.states.get("climate.thermostat")
+    assert climate_thermostat.state == HVAC_MODE_HEAT
+    assert climate_thermostat.attributes["hvac_modes"] == [
+        HVAC_MODE_HEAT,
+        HVAC_MODE_OFF,
+    ]
+    assert climate_thermostat.attributes["current_temperature"] == 21.0
+    assert climate_thermostat.attributes["temperature"] == 21.0
+    assert hass.states.get("sensor.thermostat_battery_level").state == "59"
+
+    # Event signals thermostat configured off
+
+    state_changed_event = {
+        "t": "event",
+        "e": "changed",
+        "r": "sensors",
+        "id": "0",
+        "state": {"on": False},
+    }
+    gateway.api.event_handler(state_changed_event)
+    await hass.async_block_till_done()
+
+    assert hass.states.get("climate.thermostat").state == STATE_OFF
+
+    # Event signals thermostat state on
+
+    state_changed_event = {
+        "t": "event",
+        "e": "changed",
+        "r": "sensors",
+        "id": "0",
+        "state": {"on": True},
+    }
+    gateway.api.event_handler(state_changed_event)
+    await hass.async_block_till_done()
+
+    assert hass.states.get("climate.thermostat").state == HVAC_MODE_HEAT
+
+    # Verify service calls
+
+    thermostat_device = gateway.api.sensors["0"]
+
+    # Service turn on thermostat
+
+    with patch.object(thermostat_device, "_request", return_value=True) as set_callback:
+        await hass.services.async_call(
+            CLIMATE_DOMAIN,
+            SERVICE_SET_HVAC_MODE,
+            {ATTR_ENTITY_ID: "climate.thermostat", ATTR_HVAC_MODE: HVAC_MODE_HEAT},
+            blocking=True,
+        )
+        await hass.async_block_till_done()
+        set_callback.assert_called_with("put", "/sensors/0/config", json={"on": True})
+
+    # Service turn on thermostat
+
+    with patch.object(thermostat_device, "_request", return_value=True) as set_callback:
+        await hass.services.async_call(
+            CLIMATE_DOMAIN,
+            SERVICE_SET_HVAC_MODE,
+            {ATTR_ENTITY_ID: "climate.thermostat", ATTR_HVAC_MODE: HVAC_MODE_OFF},
+            blocking=True,
+        )
+        await hass.async_block_till_done()
+        set_callback.assert_called_with("put", "/sensors/0/config", json={"on": False})
+
+    # Service set HVAC mode to unsupported value
+
+    with patch.object(
+        thermostat_device, "_request", return_value=True
+    ) as set_callback, pytest.raises(ValueError):
+        await hass.services.async_call(
+            CLIMATE_DOMAIN,
+            SERVICE_SET_HVAC_MODE,
+            {ATTR_ENTITY_ID: "climate.thermostat", ATTR_HVAC_MODE: HVAC_MODE_AUTO},
+            blocking=True,
+        )
+
+
 async def test_climate_device_without_cooling_support(hass):
     """Test successful creation of sensor entities."""
     data = deepcopy(DECONZ_WEB_REQUEST)