hass-core/tests/components/modbus/test_fan.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

350 lines
9.8 KiB
Python
Raw Normal View History

"""The tests for the Modbus fan component."""
from pymodbus.exceptions import ModbusException
import pytest
from homeassistant.components.fan import DOMAIN as FAN_DOMAIN
from homeassistant.components.modbus.const import (
CALL_TYPE_COIL,
CALL_TYPE_DISCRETE,
CALL_TYPE_REGISTER_HOLDING,
CALL_TYPE_REGISTER_INPUT,
CONF_DEVICE_ADDRESS,
CONF_FANS,
CONF_INPUT_TYPE,
CONF_STATE_OFF,
CONF_STATE_ON,
CONF_VERIFY,
CONF_WRITE_TYPE,
MODBUS_DOMAIN,
)
from homeassistant.const import (
CONF_ADDRESS,
CONF_COMMAND_OFF,
CONF_COMMAND_ON,
CONF_NAME,
CONF_SCAN_INTERVAL,
CONF_SLAVE,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant, State
from homeassistant.setup import async_setup_component
from .conftest import TEST_ENTITY_NAME, ReadResult
ENTITY_ID = f"{FAN_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_")
ENTITY_ID2 = f"{ENTITY_ID}_2"
@pytest.mark.parametrize(
"do_config",
[
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
}
]
},
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_WRITE_TYPE: CALL_TYPE_COIL,
}
]
},
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01,
CONF_VERIFY: {
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_ADDRESS: 1235,
CONF_STATE_OFF: 0,
CONF_STATE_ON: 1,
},
}
]
},
{
CONF_FANS: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_DEVICE_ADDRESS: 1,
CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01,
CONF_VERIFY: {
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_ADDRESS: 1235,
CONF_STATE_OFF: 0,
CONF_STATE_ON: 1,
},
}
]
},
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01,
CONF_VERIFY: {
CONF_INPUT_TYPE: CALL_TYPE_REGISTER_INPUT,
CONF_ADDRESS: 1235,
CONF_STATE_OFF: 0,
CONF_STATE_ON: 1,
},
}
]
},
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01,
CONF_VERIFY: {
CONF_INPUT_TYPE: CALL_TYPE_DISCRETE,
CONF_ADDRESS: 1235,
CONF_STATE_OFF: 0,
CONF_STATE_ON: 1,
},
}
]
},
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_COMMAND_OFF: 0x00,
CONF_COMMAND_ON: 0x01,
CONF_VERIFY: None,
}
]
},
],
)
async def test_config_fan(hass: HomeAssistant, mock_modbus) -> None:
"""Run configuration test for fan."""
assert FAN_DOMAIN in hass.config.components
@pytest.mark.parametrize(
"do_config",
[
{
CONF_FANS: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_WRITE_TYPE: CALL_TYPE_COIL,
},
],
},
{
CONF_FANS: [
{
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SLAVE: 1,
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
},
],
},
],
)
@pytest.mark.parametrize(
("register_words", "do_exception", "config_addon", "expected"),
[
(
[0x00],
False,
{CONF_VERIFY: {}},
STATE_OFF,
),
(
[0x01],
False,
{CONF_VERIFY: {}},
STATE_ON,
),
(
[0xFE],
False,
{CONF_VERIFY: {}},
STATE_OFF,
),
(
[0x00],
True,
{CONF_VERIFY: {}},
STATE_UNAVAILABLE,
),
(
[0x00],
True,
None,
STATE_OFF,
),
],
)
async def test_all_fan(hass: HomeAssistant, mock_do_cycle, expected) -> None:
"""Run test for given config."""
assert hass.states.get(ENTITY_ID).state == expected
@pytest.mark.parametrize(
"mock_test_state",
2021-06-30 14:34:33 +02:00
[(State(ENTITY_ID, STATE_ON),)],
indirect=True,
)
@pytest.mark.parametrize(
"do_config",
[
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_SCAN_INTERVAL: 0,
}
]
},
],
)
async def test_restore_state_fan(
hass: HomeAssistant, mock_test_state, mock_modbus
) -> None:
"""Run test for fan restore state."""
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID).state == STATE_ON
@pytest.mark.parametrize(
"do_config",
[
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 17,
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_SCAN_INTERVAL: 0,
},
{
CONF_NAME: f"{TEST_ENTITY_NAME} 2",
CONF_ADDRESS: 18,
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_SCAN_INTERVAL: 0,
CONF_VERIFY: {},
},
],
},
],
)
async def test_fan_service_turn(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
mock_modbus,
) -> None:
"""Run test for service turn_on/turn_off."""
assert MODBUS_DOMAIN in hass.config.components
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID).state == STATE_OFF
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"fan", "turn_on", service_data={"entity_id": ENTITY_ID}
)
await hass.async_block_till_done()
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID).state == STATE_ON
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"fan", "turn_off", service_data={"entity_id": ENTITY_ID}
)
await hass.async_block_till_done()
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID).state == STATE_OFF
mock_modbus.read_holding_registers.return_value = ReadResult([0x01])
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID2).state == STATE_OFF
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"fan", "turn_on", service_data={"entity_id": ENTITY_ID2}
)
await hass.async_block_till_done()
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID2).state == STATE_ON
mock_modbus.read_holding_registers.return_value = ReadResult([0x00])
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"fan", "turn_off", service_data={"entity_id": ENTITY_ID2}
)
await hass.async_block_till_done()
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID2).state == STATE_OFF
mock_modbus.write_register.side_effect = ModbusException("fail write_")
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"fan", "turn_on", service_data={"entity_id": ENTITY_ID2}
)
await hass.async_block_till_done()
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID2).state == STATE_UNAVAILABLE
mock_modbus.write_coil.side_effect = ModbusException("fail write_")
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"fan", "turn_off", service_data={"entity_id": ENTITY_ID}
)
await hass.async_block_till_done()
2021-06-30 14:34:33 +02:00
assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
@pytest.mark.parametrize(
"do_config",
[
{
CONF_FANS: [
{
2021-08-17 20:43:27 +02:00
CONF_NAME: TEST_ENTITY_NAME,
CONF_ADDRESS: 1234,
CONF_WRITE_TYPE: CALL_TYPE_COIL,
CONF_VERIFY: {},
}
]
},
],
)
2024-04-17 19:10:09 +02:00
async def test_service_fan_update(hass: HomeAssistant, mock_modbus_ha) -> None:
"""Run test for service homeassistant.update_entity."""
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"homeassistant", "update_entity", {"entity_id": ENTITY_ID}, blocking=True
)
assert hass.states.get(ENTITY_ID).state == STATE_OFF
2024-04-17 19:10:09 +02:00
mock_modbus_ha.read_coils.return_value = ReadResult([0x01])
await hass.services.async_call(
2021-06-30 14:34:33 +02:00
"homeassistant", "update_entity", {"entity_id": ENTITY_ID}, blocking=True
)
assert hass.states.get(ENTITY_ID).state == STATE_ON
async def test_no_discovery_info_fan(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test setup without discovery info."""
assert FAN_DOMAIN not in hass.config.components
assert await async_setup_component(
hass,
FAN_DOMAIN,
{FAN_DOMAIN: {"platform": MODBUS_DOMAIN}},
)
await hass.async_block_till_done()
assert FAN_DOMAIN in hass.config.components