Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow pymodbus to reconnect in running system (not startup) #53020

Merged
merged 9 commits into from Jul 19, 2021
13 changes: 8 additions & 5 deletions homeassistant/components/modbus/modbus.py
Expand Up @@ -249,17 +249,22 @@ async def async_setup(self):
for entry in self._pb_call.values():
entry[ENTRY_FUNC] = getattr(self._client, entry[ENTRY_NAME])

await self.async_connect_task()
return True

async def async_connect_task(self):
"""Try to connect, and retry if needed."""
async with self._lock:
if not await self.hass.async_add_executor_job(self._pymodbus_connect):
self._log_error("initial connect failed, no retry", error_state=False)
return False
err = f"{self._config_name} connect failed, retry in pymodbus"
self._log_error(err, error_state=False)
return

# Start counting down to allow modbus requests.
if self._config_delay:
self._async_cancel_listener = async_call_later(
self.hass, self._config_delay, self.async_end_delay
)
return True

@callback
janiversen marked this conversation as resolved.
Show resolved Hide resolved
def async_end_delay(self, args):
Expand Down Expand Up @@ -313,8 +318,6 @@ async def async_pymodbus_call(self, unit, address, value, use_call):
return None
if not self._client:
return None
if not self._client.is_socket_open():
return None
async with self._lock:
result = await self.hass.async_add_executor_job(
self._pymodbus_call, unit, address, value, use_call
Expand Down
67 changes: 0 additions & 67 deletions tests/components/modbus/test_init.py
Expand Up @@ -515,35 +515,6 @@ async def test_pymodbus_constructor_fail(hass, caplog):
assert mock_pb.called


@pytest.mark.parametrize(
"do_connect,do_exception,do_text",
[
[False, None, "initial connect failed, no retry"],
[True, ModbusException("no connect"), "Modbus Error: no connect"],
],
)
async def test_pymodbus_connect_fail(
hass, do_connect, do_exception, do_text, caplog, mock_pymodbus
):
"""Run test for failing pymodbus connect."""
config = {
DOMAIN: [
{
CONF_TYPE: "tcp",
CONF_HOST: TEST_HOST,
CONF_PORT: 5501,
}
]
}
caplog.set_level(logging.ERROR)
mock_pymodbus.connect.return_value = do_connect
mock_pymodbus.connect.side_effect = do_exception
assert await async_setup_component(hass, DOMAIN, config) is False
await hass.async_block_till_done()
assert caplog.messages[0].startswith(f"Pymodbus: {do_text}")
assert caplog.records[0].levelname == "ERROR"


async def test_pymodbus_close_fail(hass, caplog, mock_pymodbus):
"""Run test for failing pymodbus close."""
config = {
Expand All @@ -563,44 +534,6 @@ async def test_pymodbus_close_fail(hass, caplog, mock_pymodbus):
# Close() is called as part of teardown


async def test_disconnect(hass, mock_pymodbus):
"""Run test for startup delay."""

# the purpose of this test is to test a device disconnect
# We "hijiack" a binary_sensor to make a proper blackbox test.
entity_id = f"{BINARY_SENSOR_DOMAIN}.{TEST_SENSOR_NAME}"
config = {
DOMAIN: [
{
CONF_TYPE: "tcp",
CONF_HOST: TEST_HOST,
CONF_PORT: 5501,
CONF_NAME: TEST_MODBUS_NAME,
CONF_BINARY_SENSORS: [
{
CONF_INPUT_TYPE: CALL_TYPE_COIL,
CONF_NAME: f"{TEST_SENSOR_NAME}",
CONF_ADDRESS: 52,
},
],
}
]
}
mock_pymodbus.read_coils.return_value = ReadResult([0x01])
mock_pymodbus.is_socket_open.return_value = False
now = dt_util.utcnow()
with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
assert await async_setup_component(hass, DOMAIN, config) is True
await hass.async_block_till_done()

# pass first scan_interval
now = now + timedelta(seconds=20)
with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
async_fire_time_changed(hass, now)
await hass.async_block_till_done()
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE


async def test_delay(hass, mock_pymodbus):
"""Run test for startup delay."""

Expand Down