243 lines
8.2 KiB
Python
243 lines
8.2 KiB
Python
"""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
|
|
)
|