From d25f45a957327a94489f697c96b2425b2d5def55 Mon Sep 17 00:00:00 2001 From: jan iversen Date: Sat, 16 Sep 2023 09:57:55 +0200 Subject: [PATCH] Harden modbus against lib errors (#100469) --- homeassistant/components/modbus/modbus.py | 6 ++++++ tests/components/modbus/conftest.py | 9 +++++++++ tests/components/modbus/test_fan.py | 5 ++++- tests/components/modbus/test_light.py | 5 ++++- tests/components/modbus/test_switch.py | 9 +++++++-- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/modbus/modbus.py b/homeassistant/components/modbus/modbus.py index a503b71593c..31179a23583 100644 --- a/homeassistant/components/modbus/modbus.py +++ b/homeassistant/components/modbus/modbus.py @@ -419,9 +419,15 @@ class ModbusHub: except ModbusException as exception_error: self._log_error(str(exception_error)) return None + if not result: + self._log_error("Error: pymodbus returned None") + return None if not hasattr(result, entry.attr): self._log_error(str(result)) return None + if result.isError(): # type: ignore[no-untyped-call] + self._log_error("Error: pymodbus returned isError True") + return None self._in_error = False return result diff --git a/tests/components/modbus/conftest.py b/tests/components/modbus/conftest.py index a08743b7e6c..460b1eb5dd3 100644 --- a/tests/components/modbus/conftest.py +++ b/tests/components/modbus/conftest.py @@ -32,6 +32,11 @@ class ReadResult: """Init.""" self.registers = register_words self.bits = register_words + self.value = register_words + + def isError(self): + """Set error state.""" + return False @pytest.fixture(name="mock_pymodbus") @@ -136,6 +141,10 @@ async def mock_pymodbus_return_fixture(hass, register_words, mock_modbus): mock_modbus.read_discrete_inputs.return_value = read_result mock_modbus.read_input_registers.return_value = read_result mock_modbus.read_holding_registers.return_value = read_result + mock_modbus.write_register.return_value = read_result + mock_modbus.write_registers.return_value = read_result + mock_modbus.write_coil.return_value = read_result + mock_modbus.write_coils.return_value = read_result @pytest.fixture(name="mock_do_cycle") diff --git a/tests/components/modbus/test_fan.py b/tests/components/modbus/test_fan.py index e47ed5c2371..932e07b2d1a 100644 --- a/tests/components/modbus/test_fan.py +++ b/tests/components/modbus/test_fan.py @@ -261,7 +261,10 @@ async def test_restore_state_fan( ], ) async def test_fan_service_turn( - hass: HomeAssistant, caplog: pytest.LogCaptureFixture, mock_modbus + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, + mock_modbus, + mock_pymodbus_return, ) -> None: """Run test for service turn_on/turn_off.""" diff --git a/tests/components/modbus/test_light.py b/tests/components/modbus/test_light.py index a5871bdbd67..1d6963aaa12 100644 --- a/tests/components/modbus/test_light.py +++ b/tests/components/modbus/test_light.py @@ -260,7 +260,10 @@ async def test_restore_state_light( ], ) async def test_light_service_turn( - hass: HomeAssistant, caplog: pytest.LogCaptureFixture, mock_modbus + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, + mock_modbus, + mock_pymodbus_return, ) -> None: """Run test for service turn_on/turn_off.""" diff --git a/tests/components/modbus/test_switch.py b/tests/components/modbus/test_switch.py index ff7d6860f3b..0eb40d2c082 100644 --- a/tests/components/modbus/test_switch.py +++ b/tests/components/modbus/test_switch.py @@ -316,7 +316,10 @@ async def test_restore_state_switch( ], ) async def test_switch_service_turn( - hass: HomeAssistant, caplog: pytest.LogCaptureFixture, mock_modbus + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, + mock_modbus, + mock_pymodbus_return, ) -> None: """Run test for service turn_on/turn_off.""" assert MODBUS_DOMAIN in hass.config.components @@ -407,7 +410,9 @@ async def test_service_switch_update(hass: HomeAssistant, mock_modbus, mock_ha) }, ], ) -async def test_delay_switch(hass: HomeAssistant, mock_modbus) -> None: +async def test_delay_switch( + hass: HomeAssistant, mock_modbus, mock_pymodbus_return +) -> None: """Run test for switch verify delay.""" mock_modbus.read_holding_registers.return_value = ReadResult([0x01]) now = dt_util.utcnow()