Check for duplicate entity name/address in modbus entities (#54669)

* Check for duplicate entity name/address.
This commit is contained in:
jan iversen 2021-08-19 09:37:31 +02:00 committed by GitHub
parent faec82ae8f
commit 0688aaa2b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 5 deletions

View File

@ -116,7 +116,12 @@ from .const import (
UDP,
)
from .modbus import ModbusHub, async_modbus_setup
from .validators import number_validator, scan_interval_validator, struct_validator
from .validators import (
duplicate_entity_validator,
number_validator,
scan_interval_validator,
struct_validator,
)
_LOGGER = logging.getLogger(__name__)
@ -327,6 +332,7 @@ CONFIG_SCHEMA = vol.Schema(
DOMAIN: vol.All(
cv.ensure_list,
scan_interval_validator,
duplicate_entity_validator,
[
vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA),
],

View File

@ -9,9 +9,11 @@ from typing import Any
import voluptuous as vol
from homeassistant.const import (
CONF_ADDRESS,
CONF_COUNT,
CONF_NAME,
CONF_SCAN_INTERVAL,
CONF_SLAVE,
CONF_STRUCTURE,
CONF_TIMEOUT,
)
@ -189,3 +191,35 @@ def scan_interval_validator(config: dict) -> dict:
)
hub[CONF_TIMEOUT] = minimum_scan_interval - 1
return config
def duplicate_entity_validator(config: dict) -> dict:
"""Control scan_interval."""
for hub_index, hub in enumerate(config):
addresses: set[str] = set()
for component, conf_key in PLATFORMS:
if conf_key not in hub:
continue
names: set[str] = set()
errors: list[int] = []
for index, entry in enumerate(hub[conf_key]):
name = entry[CONF_NAME]
addr = str(entry[CONF_ADDRESS])
if CONF_SLAVE in entry:
addr += "_" + str(entry[CONF_SLAVE])
if addr in addresses:
err = f"Modbus {component}/{name} address {addr} is duplicate, second entry not loaded!"
_LOGGER.warning(err)
errors.append(index)
elif name in names:
err = f"Modbus {component}/{name}  is duplicate, second entry not loaded!"
_LOGGER.warning(err)
errors.append(index)
else:
names.add(name)
addresses.add(addr)
for i in reversed(errors):
del config[hub_index][conf_key][i]
return config

View File

@ -235,7 +235,7 @@ async def test_restore_state_cover(hass, mock_test_state, mock_modbus):
{
CONF_NAME: f"{TEST_ENTITY_NAME}2",
CONF_INPUT_TYPE: CALL_TYPE_COIL,
CONF_ADDRESS: 1234,
CONF_ADDRESS: 1235,
CONF_SCAN_INTERVAL: 0,
},
]

View File

@ -231,7 +231,7 @@ async def test_fan_service_turn(hass, caplog, mock_pymodbus):
},
{
CONF_NAME: f"{TEST_ENTITY_NAME}2",
CONF_ADDRESS: 17,
CONF_ADDRESS: 18,
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_SCAN_INTERVAL: 0,
CONF_VERIFY: {},

View File

@ -231,7 +231,7 @@ async def test_light_service_turn(hass, caplog, mock_pymodbus):
},
{
CONF_NAME: f"{TEST_ENTITY_NAME}2",
CONF_ADDRESS: 17,
CONF_ADDRESS: 18,
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_SCAN_INTERVAL: 0,
CONF_VERIFY: {},

View File

@ -245,7 +245,7 @@ async def test_switch_service_turn(hass, caplog, mock_pymodbus):
},
{
CONF_NAME: f"{TEST_ENTITY_NAME}2",
CONF_ADDRESS: 17,
CONF_ADDRESS: 18,
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
CONF_SCAN_INTERVAL: 0,
CONF_VERIFY: {},