"""Test KNX climate.""" from homeassistant.components.climate import PRESET_ECO, PRESET_SLEEP, HVACMode from homeassistant.components.knx.schema import ClimateSchema from homeassistant.const import CONF_NAME, STATE_IDLE from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.setup import async_setup_component from .conftest import KNXTestKit from tests.common import async_capture_events RAW_FLOAT_20_0 = (0x07, 0xD0) RAW_FLOAT_21_0 = (0x0C, 0x1A) RAW_FLOAT_22_0 = (0x0C, 0x4C) async def test_climate_basic_temperature_set( hass: HomeAssistant, knx: KNXTestKit ) -> None: """Test KNX climate basic.""" await knx.setup_integration( { ClimateSchema.PLATFORM: { CONF_NAME: "test", ClimateSchema.CONF_TEMPERATURE_ADDRESS: "1/2/3", ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS: "1/2/4", ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS: "1/2/5", } } ) events = async_capture_events(hass, "state_changed") # read temperature await knx.assert_read("1/2/3") # read target temperature await knx.assert_read("1/2/5") # StateUpdater initialize state await knx.receive_response("1/2/3", RAW_FLOAT_21_0) await knx.receive_response("1/2/5", RAW_FLOAT_22_0) events.clear() # set new temperature await hass.services.async_call( "climate", "set_temperature", {"entity_id": "climate.test", "temperature": 20}, blocking=True, ) await knx.assert_write("1/2/4", RAW_FLOAT_20_0) assert len(events) == 1 async def test_climate_hvac_mode(hass: HomeAssistant, knx: KNXTestKit) -> None: """Test KNX climate hvac mode.""" await knx.setup_integration( { ClimateSchema.PLATFORM: { CONF_NAME: "test", ClimateSchema.CONF_TEMPERATURE_ADDRESS: "1/2/3", ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS: "1/2/4", ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS: "1/2/5", ClimateSchema.CONF_CONTROLLER_MODE_ADDRESS: "1/2/6", ClimateSchema.CONF_CONTROLLER_MODE_STATE_ADDRESS: "1/2/7", ClimateSchema.CONF_ON_OFF_ADDRESS: "1/2/8", ClimateSchema.CONF_OPERATION_MODES: ["Auto"], } } ) async_capture_events(hass, "state_changed") await hass.async_block_till_done() # read states state updater await knx.assert_read("1/2/7") await knx.assert_read("1/2/3") # StateUpdater initialize state await knx.receive_response("1/2/7", (0x01,)) await knx.receive_response("1/2/3", RAW_FLOAT_20_0) # StateUpdater semaphore allows 2 concurrent requests # read target temperature state await knx.assert_read("1/2/5") await knx.receive_response("1/2/5", RAW_FLOAT_22_0) # turn hvac off await hass.services.async_call( "climate", "set_hvac_mode", {"entity_id": "climate.test", "hvac_mode": HVACMode.OFF}, blocking=True, ) await knx.assert_write("1/2/8", False) # turn hvac on await hass.services.async_call( "climate", "set_hvac_mode", {"entity_id": "climate.test", "hvac_mode": HVACMode.HEAT}, blocking=True, ) await knx.assert_write("1/2/8", True) await knx.assert_write("1/2/6", (0x01,)) async def test_climate_preset_mode( hass: HomeAssistant, knx: KNXTestKit, entity_registry: er.EntityRegistry ) -> None: """Test KNX climate preset mode.""" await knx.setup_integration( { ClimateSchema.PLATFORM: { CONF_NAME: "test", ClimateSchema.CONF_TEMPERATURE_ADDRESS: "1/2/3", ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS: "1/2/4", ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS: "1/2/5", ClimateSchema.CONF_OPERATION_MODE_ADDRESS: "1/2/6", ClimateSchema.CONF_OPERATION_MODE_STATE_ADDRESS: "1/2/7", } } ) events = async_capture_events(hass, "state_changed") await hass.async_block_till_done() # read states state updater await knx.assert_read("1/2/7") await knx.assert_read("1/2/3") # StateUpdater initialize state await knx.receive_response("1/2/7", (0x01,)) await knx.receive_response("1/2/3", RAW_FLOAT_21_0) # StateUpdater semaphore allows 2 concurrent requests # read target temperature state await knx.assert_read("1/2/5") await knx.receive_response("1/2/5", RAW_FLOAT_22_0) events.clear() # set preset mode await hass.services.async_call( "climate", "set_preset_mode", {"entity_id": "climate.test", "preset_mode": PRESET_ECO}, blocking=True, ) await knx.assert_write("1/2/6", (0x04,)) assert len(events) == 1 events.pop() # set preset mode await hass.services.async_call( "climate", "set_preset_mode", {"entity_id": "climate.test", "preset_mode": PRESET_SLEEP}, blocking=True, ) await knx.assert_write("1/2/6", (0x03,)) assert len(events) == 1 events.pop() assert len(knx.xknx.devices) == 2 assert len(knx.xknx.devices[0].device_updated_cbs) == 2 assert len(knx.xknx.devices[1].device_updated_cbs) == 2 # test removing also removes hooks entity_registry.async_remove("climate.test") await hass.async_block_till_done() # If we remove the entity the underlying devices should disappear too assert len(knx.xknx.devices) == 0 async def test_update_entity(hass: HomeAssistant, knx: KNXTestKit) -> None: """Test update climate entity for KNX.""" await knx.setup_integration( { ClimateSchema.PLATFORM: { CONF_NAME: "test", ClimateSchema.CONF_TEMPERATURE_ADDRESS: "1/2/3", ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS: "1/2/4", ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS: "1/2/5", ClimateSchema.CONF_OPERATION_MODE_ADDRESS: "1/2/6", ClimateSchema.CONF_OPERATION_MODE_STATE_ADDRESS: "1/2/7", } } ) assert await async_setup_component(hass, "homeassistant", {}) await hass.async_block_till_done() async_capture_events(hass, "state_changed") await hass.async_block_till_done() # read states state updater await knx.assert_read("1/2/7") await knx.assert_read("1/2/3") # StateUpdater initialize state await knx.receive_response("1/2/7", (0x01,)) await knx.receive_response("1/2/3", RAW_FLOAT_21_0) # StateUpdater semaphore allows 2 concurrent requests await knx.assert_read("1/2/5") await knx.receive_response("1/2/5", RAW_FLOAT_22_0) # verify update entity retriggers group value reads to the bus await hass.services.async_call( "homeassistant", "update_entity", target={"entity_id": "climate.test"}, blocking=True, ) await knx.assert_read("1/2/3") await knx.assert_read("1/2/5") await knx.assert_read("1/2/7") async def test_command_value_idle_mode(hass: HomeAssistant, knx: KNXTestKit) -> None: """Test KNX climate command_value.""" await knx.setup_integration( { ClimateSchema.PLATFORM: { CONF_NAME: "test", ClimateSchema.CONF_TEMPERATURE_ADDRESS: "1/2/3", ClimateSchema.CONF_TARGET_TEMPERATURE_ADDRESS: "1/2/4", ClimateSchema.CONF_TARGET_TEMPERATURE_STATE_ADDRESS: "1/2/5", ClimateSchema.CONF_COMMAND_VALUE_STATE_ADDRESS: "1/2/6", } } ) await hass.async_block_till_done() # read states state updater await knx.assert_read("1/2/3") await knx.assert_read("1/2/5") # StateUpdater initialize state await knx.receive_response("1/2/5", RAW_FLOAT_22_0) await knx.receive_response("1/2/3", RAW_FLOAT_21_0) # StateUpdater semaphore allows 2 concurrent requests await knx.assert_read("1/2/6") await knx.receive_response("1/2/6", (0x32,)) knx.assert_state("climate.test", HVACMode.HEAT, command_value=20) await knx.receive_write("1/2/6", (0x00,)) knx.assert_state( "climate.test", HVACMode.HEAT, command_value=0, hvac_action=STATE_IDLE )