diff --git a/homeassistant/components/modbus/modbus.py b/homeassistant/components/modbus/modbus.py index 28249ce72ad..d955c6656f8 100644 --- a/homeassistant/components/modbus/modbus.py +++ b/homeassistant/components/modbus/modbus.py @@ -131,6 +131,8 @@ async def async_modbus_setup( if config[DOMAIN]: config[DOMAIN] = check_config(hass, config[DOMAIN]) + if not config[DOMAIN]: + return False if DOMAIN in hass.data and config[DOMAIN] == []: hubs = hass.data[DOMAIN] for name in hubs: diff --git a/homeassistant/components/modbus/strings.json b/homeassistant/components/modbus/strings.json index d4f649ac1e6..fd93185b891 100644 --- a/homeassistant/components/modbus/strings.json +++ b/homeassistant/components/modbus/strings.json @@ -93,6 +93,10 @@ "duplicate_entity_name": { "title": "Modbus {sub_1} is duplicate, second entry not loaded.", "description": "A entity name must be unique, Please correct the entry in your configuration.yaml file and restart Home Assistant to fix this issue." + }, + "no_entities": { + "title": "Modbus {sub_1} contain no entities, entry not loaded.", + "description": "Please add at least one entity to Modbus {sub_1} in your configuration.yaml file and restart Home Assistant to fix this issue." } } } diff --git a/homeassistant/components/modbus/validators.py b/homeassistant/components/modbus/validators.py index a91ac9be6b4..7de2ecbe604 100644 --- a/homeassistant/components/modbus/validators.py +++ b/homeassistant/components/modbus/validators.py @@ -490,10 +490,18 @@ def check_config(hass: HomeAssistant, config: dict) -> dict: else: entity_inx += 1 if no_entities: - err = f"Modbus {hub[CONF_NAME]} contain no entities, this will cause instability, please add at least one entity!" - _LOGGER.warning(err) - # Ensure timeout is not started/handled. - hub[CONF_TIMEOUT] = -1 + modbus_create_issue( + hass, + "no_entities", + [ + hub[CONF_NAME], + "", + "", + ], + f"Modbus {hub[CONF_NAME]} contain no entities, causing instability, entry not loaded", + ) + del config[hub_inx] + continue if hub[CONF_TIMEOUT] >= minimum_scan_interval: hub[CONF_TIMEOUT] = minimum_scan_interval - 1 _LOGGER.warning( diff --git a/tests/components/modbus/test_init.py b/tests/components/modbus/test_init.py index e55b9f4232d..44bf089f0d5 100644 --- a/tests/components/modbus/test_init.py +++ b/tests/components/modbus/test_init.py @@ -962,22 +962,46 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, CONF_RETRIES: 3, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: TCP, @@ -986,11 +1010,23 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_NAME: TEST_MODBUS_NAME, CONF_TIMEOUT: 30, CONF_DELAY: 10, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: UDP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: UDP, @@ -999,11 +1035,23 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_NAME: TEST_MODBUS_NAME, CONF_TIMEOUT: 30, CONF_DELAY: 10, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: RTUOVERTCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: RTUOVERTCP, @@ -1012,6 +1060,12 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_NAME: TEST_MODBUS_NAME, CONF_TIMEOUT: 30, CONF_DELAY: 10, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: SERIAL, @@ -1022,6 +1076,12 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_PARITY: "E", CONF_STOPBITS: 1, CONF_MSG_WAIT: 100, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: SERIAL, @@ -1034,12 +1094,24 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_NAME: TEST_MODBUS_NAME, CONF_TIMEOUT: 30, CONF_DELAY: 10, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, CONF_DELAY: 5, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, [ { @@ -1047,12 +1119,24 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, CONF_NAME: TEST_MODBUS_NAME, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, CONF_NAME: f"{TEST_MODBUS_NAME} 2", + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, { CONF_TYPE: SERIAL, @@ -1063,6 +1147,12 @@ async def test_no_duplicate_names(hass: HomeAssistant, do_config) -> None: CONF_PARITY: "E", CONF_STOPBITS: 1, CONF_NAME: f"{TEST_MODBUS_NAME} 3", + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], }, ], { @@ -1351,6 +1441,12 @@ async def test_pymodbus_close_fail( CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], } ] } @@ -1373,6 +1469,12 @@ async def test_pymodbus_connect_fail( CONF_TYPE: TCP, CONF_HOST: TEST_MODBUS_HOST, CONF_PORT: TEST_PORT_TCP, + CONF_SENSORS: [ + { + CONF_NAME: "dummy", + CONF_ADDRESS: 9999, + } + ], } ] } @@ -1603,3 +1705,18 @@ async def test_integration_setup_failed( ) await hass.services.async_call(DOMAIN, SERVICE_RELOAD, blocking=True) await hass.async_block_till_done() + + +async def test_no_entities(hass: HomeAssistant) -> None: + """Run test for failing pymodbus constructor.""" + config = { + DOMAIN: [ + { + CONF_NAME: TEST_MODBUS_NAME, + CONF_TYPE: TCP, + CONF_HOST: TEST_MODBUS_HOST, + CONF_PORT: TEST_PORT_TCP, + } + ] + } + assert await async_setup_component(hass, DOMAIN, config) is False