From 89cdda9fe6a1a5af52088e15e36f89b80685d94b Mon Sep 17 00:00:00 2001
From: Matthias Alphart <farmio@alphart.net>
Date: Sun, 27 Jun 2021 18:31:07 +0200
Subject: [PATCH] Add idle hvac_action to KNX climate (#52006)

* add idle hvac_action and command_value extra_state_attribute

* use class attribute for unit
---
 homeassistant/components/knx/climate.py | 18 +++++++++++++++++-
 homeassistant/components/knx/schema.py  |  4 ++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/homeassistant/components/knx/climate.py b/homeassistant/components/knx/climate.py
index b43f0efe7f0..aeef4a35c29 100644
--- a/homeassistant/components/knx/climate.py
+++ b/homeassistant/components/knx/climate.py
@@ -28,6 +28,7 @@ from .const import CONTROLLER_MODES, CURRENT_HVAC_ACTIONS, DOMAIN, PRESET_MODES
 from .knx_entity import KnxEntity
 from .schema import ClimateSchema
 
+ATTR_COMMAND_VALUE = "command_value"
 CONTROLLER_MODES_INV = {value: key for key, value in CONTROLLER_MODES.items()}
 PRESET_MODES_INV = {value: key for key, value in PRESET_MODES.items()}
 
@@ -156,10 +157,14 @@ def _create_climate(xknx: XKNX, config: ConfigType) -> XknxClimate:
         temperature_step=config[ClimateSchema.CONF_TEMPERATURE_STEP],
         group_address_on_off=config.get(ClimateSchema.CONF_ON_OFF_ADDRESS),
         group_address_on_off_state=config.get(ClimateSchema.CONF_ON_OFF_STATE_ADDRESS),
+        on_off_invert=config[ClimateSchema.CONF_ON_OFF_INVERT],
+        group_address_active_state=config.get(ClimateSchema.CONF_ACTIVE_STATE_ADDRESS),
+        group_address_command_value_state=config.get(
+            ClimateSchema.CONF_COMMAND_VALUE_STATE_ADDRESS
+        ),
         min_temp=config.get(ClimateSchema.CONF_MIN_TEMP),
         max_temp=config.get(ClimateSchema.CONF_MAX_TEMP),
         mode=climate_mode,
-        on_off_invert=config[ClimateSchema.CONF_ON_OFF_INVERT],
     )
 
 
@@ -256,6 +261,8 @@ class KNXClimate(KnxEntity, ClimateEntity):
         """
         if self._device.supports_on_off and not self._device.is_on:
             return CURRENT_HVAC_OFF
+        if self._device.is_active is False:
+            return CURRENT_HVAC_IDLE
         if self._device.mode is not None and self._device.mode.supports_controller_mode:
             return CURRENT_HVAC_ACTIONS.get(
                 self._device.mode.controller_mode.value, CURRENT_HVAC_IDLE
@@ -311,6 +318,15 @@ class KNXClimate(KnxEntity, ClimateEntity):
             await self._device.mode.set_operation_mode(knx_operation_mode)
             self.async_write_ha_state()
 
+    @property
+    def extra_state_attributes(self) -> dict[str, Any] | None:
+        """Return device specific state attributes."""
+        attr: dict[str, Any] = {}
+
+        if self._device.command_value.initialized:
+            attr[ATTR_COMMAND_VALUE] = self._device.command_value.value
+        return attr
+
     async def async_added_to_hass(self) -> None:
         """Store register state change callback."""
         await super().async_added_to_hass()
diff --git a/homeassistant/components/knx/schema.py b/homeassistant/components/knx/schema.py
index f863efec685..4604eaf1096 100644
--- a/homeassistant/components/knx/schema.py
+++ b/homeassistant/components/knx/schema.py
@@ -259,6 +259,7 @@ class ClimateSchema(KNXPlatformSchema):
 
     PLATFORM_NAME = SupportedPlatforms.CLIMATE.value
 
+    CONF_ACTIVE_STATE_ADDRESS = "active_state_address"
     CONF_SETPOINT_SHIFT_ADDRESS = "setpoint_shift_address"
     CONF_SETPOINT_SHIFT_STATE_ADDRESS = "setpoint_shift_state_address"
     CONF_SETPOINT_SHIFT_MODE = "setpoint_shift_mode"
@@ -274,6 +275,7 @@ class ClimateSchema(KNXPlatformSchema):
     CONF_CONTROLLER_STATUS_STATE_ADDRESS = "controller_status_state_address"
     CONF_CONTROLLER_MODE_ADDRESS = "controller_mode_address"
     CONF_CONTROLLER_MODE_STATE_ADDRESS = "controller_mode_state_address"
+    CONF_COMMAND_VALUE_STATE_ADDRESS = "command_value_state_address"
     CONF_HEAT_COOL_ADDRESS = "heat_cool_address"
     CONF_HEAT_COOL_STATE_ADDRESS = "heat_cool_state_address"
     CONF_OPERATION_MODE_FROST_PROTECTION_ADDRESS = (
@@ -332,6 +334,8 @@ class ClimateSchema(KNXPlatformSchema):
                 vol.Optional(CONF_SETPOINT_SHIFT_MODE): vol.Maybe(
                     vol.All(vol.Upper, cv.enum(SetpointShiftMode))
                 ),
+                vol.Optional(CONF_ACTIVE_STATE_ADDRESS): ga_list_validator,
+                vol.Optional(CONF_COMMAND_VALUE_STATE_ADDRESS): ga_list_validator,
                 vol.Optional(CONF_OPERATION_MODE_ADDRESS): ga_list_validator,
                 vol.Optional(CONF_OPERATION_MODE_STATE_ADDRESS): ga_list_validator,
                 vol.Optional(CONF_CONTROLLER_STATUS_ADDRESS): ga_list_validator,