diff --git a/.coveragerc b/.coveragerc index b892dd1f25d..1f1efb96e7b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -706,7 +706,6 @@ omit = homeassistant/components/mjpeg/camera.py homeassistant/components/mjpeg/util.py homeassistant/components/mochad/* - homeassistant/components/modbus/climate.py homeassistant/components/modem_callerid/button.py homeassistant/components/modem_callerid/sensor.py homeassistant/components/moehlenhoff_alpha2/__init__.py diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index eb55066390b..41a1e37425e 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -336,6 +336,8 @@ def get_hub(hass: HomeAssistant, name: str) -> ModbusHub: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up Modbus component.""" + if DOMAIN not in config: + return True return await async_modbus_setup( hass, config, diff --git a/homeassistant/components/modbus/climate.py b/homeassistant/components/modbus/climate.py index 0ecfc7b43b6..7db416cfef3 100644 --- a/homeassistant/components/modbus/climate.py +++ b/homeassistant/components/modbus/climate.py @@ -28,7 +28,6 @@ from . import get_hub from .base_platform import BaseStructPlatform from .const import ( CALL_TYPE_REGISTER_HOLDING, - CALL_TYPE_WRITE_REGISTER, CALL_TYPE_WRITE_REGISTERS, CONF_CLIMATES, CONF_MAX_TEMP, @@ -103,8 +102,6 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): async def async_set_temperature(self, **kwargs: Any) -> None: """Set new target temperature.""" - if ATTR_TEMPERATURE not in kwargs: - return target_temperature = ( float(kwargs[ATTR_TEMPERATURE]) - self._offset ) / self._scale @@ -124,20 +121,12 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity): ] registers = self._swap_registers(raw_regs) - if isinstance(registers, list): - result = await self._hub.async_pymodbus_call( - self._slave, - self._target_temperature_register, - [int(float(i)) for i in registers], - CALL_TYPE_WRITE_REGISTERS, - ) - else: - result = await self._hub.async_pymodbus_call( - self._slave, - self._target_temperature_register, - target_temperature, - CALL_TYPE_WRITE_REGISTER, - ) + result = await self._hub.async_pymodbus_call( + self._slave, + self._target_temperature_register, + [int(float(i)) for i in registers], + CALL_TYPE_WRITE_REGISTERS, + ) self._attr_available = result is not None await self.async_update() diff --git a/tests/components/modbus/test_climate.py b/tests/components/modbus/test_climate.py index e453e3d4d44..54888e069ed 100644 --- a/tests/components/modbus/test_climate.py +++ b/tests/components/modbus/test_climate.py @@ -8,6 +8,7 @@ from homeassistant.components.modbus.const import ( CONF_DATA_TYPE, CONF_LAZY_ERROR, CONF_TARGET_TEMP, + MODBUS_DOMAIN, DataType, ) from homeassistant.const import ( @@ -16,10 +17,12 @@ from homeassistant.const import ( CONF_NAME, CONF_SCAN_INTERVAL, CONF_SLAVE, + STATE_UNAVAILABLE, ) from homeassistant.core import State +from homeassistant.setup import async_setup_component -from .conftest import TEST_ENTITY_NAME, ReadResult +from .conftest import TEST_ENTITY_NAME, ReadResult, do_next_cycle ENTITY_ID = f"{CLIMATE_DOMAIN}.{TEST_ENTITY_NAME}".replace(" ", "_") @@ -222,3 +225,91 @@ async def test_restore_state_climate(hass, mock_test_state, mock_modbus): state = hass.states.get(ENTITY_ID) assert state.state == HVAC_MODE_AUTO assert state.attributes[ATTR_TEMPERATURE] == 37 + + +@pytest.mark.parametrize( + "do_config", + [ + { + CONF_CLIMATES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_TARGET_TEMP: 117, + CONF_ADDRESS: 117, + CONF_SLAVE: 10, + CONF_LAZY_ERROR: 1, + } + ], + }, + ], +) +@pytest.mark.parametrize( + "register_words,do_exception,start_expect,end_expect", + [ + ( + [0x8000], + True, + "17", + STATE_UNAVAILABLE, + ), + ], +) +async def test_lazy_error_climate(hass, mock_do_cycle, start_expect, end_expect): + """Run test for sensor.""" + hass.states.async_set(ENTITY_ID, 17) + await hass.async_block_till_done() + now = mock_do_cycle + assert hass.states.get(ENTITY_ID).state == start_expect + now = await do_next_cycle(hass, now, 11) + assert hass.states.get(ENTITY_ID).state == start_expect + now = await do_next_cycle(hass, now, 11) + assert hass.states.get(ENTITY_ID).state == end_expect + + +@pytest.mark.parametrize( + "do_config", + [ + { + CONF_CLIMATES: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_TARGET_TEMP: 117, + CONF_ADDRESS: 117, + CONF_SLAVE: 10, + } + ], + }, + ], +) +@pytest.mark.parametrize( + "config_addon,register_words", + [ + ( + { + CONF_DATA_TYPE: DataType.INT16, + }, + [7, 9], + ), + ( + { + CONF_DATA_TYPE: DataType.INT32, + }, + [7], + ), + ], +) +async def test_wrong_unpack_climate(hass, mock_do_cycle): + """Run test for sensor.""" + assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE + + +async def test_no_discovery_info(hass, caplog): + """Test setup without discovery info.""" + assert CLIMATE_DOMAIN not in hass.config.components + assert await async_setup_component( + hass, + CLIMATE_DOMAIN, + {CLIMATE_DOMAIN: {"platform": MODBUS_DOMAIN}}, + ) + await hass.async_block_till_done() + assert CLIMATE_DOMAIN in hass.config.components