mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 05:37:44 +00:00
Check for duplicate entity name/address in modbus entities (#54669)
* Check for duplicate entity name/address.
This commit is contained in:
parent
faec82ae8f
commit
0688aaa2b6
@ -116,7 +116,12 @@ from .const import (
|
|||||||
UDP,
|
UDP,
|
||||||
)
|
)
|
||||||
from .modbus import ModbusHub, async_modbus_setup
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -327,6 +332,7 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
DOMAIN: vol.All(
|
DOMAIN: vol.All(
|
||||||
cv.ensure_list,
|
cv.ensure_list,
|
||||||
scan_interval_validator,
|
scan_interval_validator,
|
||||||
|
duplicate_entity_validator,
|
||||||
[
|
[
|
||||||
vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA),
|
vol.Any(SERIAL_SCHEMA, ETHERNET_SCHEMA),
|
||||||
],
|
],
|
||||||
|
@ -9,9 +9,11 @@ from typing import Any
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
CONF_ADDRESS,
|
||||||
CONF_COUNT,
|
CONF_COUNT,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_SCAN_INTERVAL,
|
CONF_SCAN_INTERVAL,
|
||||||
|
CONF_SLAVE,
|
||||||
CONF_STRUCTURE,
|
CONF_STRUCTURE,
|
||||||
CONF_TIMEOUT,
|
CONF_TIMEOUT,
|
||||||
)
|
)
|
||||||
@ -189,3 +191,35 @@ def scan_interval_validator(config: dict) -> dict:
|
|||||||
)
|
)
|
||||||
hub[CONF_TIMEOUT] = minimum_scan_interval - 1
|
hub[CONF_TIMEOUT] = minimum_scan_interval - 1
|
||||||
return config
|
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
|
||||||
|
@ -235,7 +235,7 @@ async def test_restore_state_cover(hass, mock_test_state, mock_modbus):
|
|||||||
{
|
{
|
||||||
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
||||||
CONF_INPUT_TYPE: CALL_TYPE_COIL,
|
CONF_INPUT_TYPE: CALL_TYPE_COIL,
|
||||||
CONF_ADDRESS: 1234,
|
CONF_ADDRESS: 1235,
|
||||||
CONF_SCAN_INTERVAL: 0,
|
CONF_SCAN_INTERVAL: 0,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -231,7 +231,7 @@ async def test_fan_service_turn(hass, caplog, mock_pymodbus):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
||||||
CONF_ADDRESS: 17,
|
CONF_ADDRESS: 18,
|
||||||
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||||
CONF_SCAN_INTERVAL: 0,
|
CONF_SCAN_INTERVAL: 0,
|
||||||
CONF_VERIFY: {},
|
CONF_VERIFY: {},
|
||||||
|
@ -231,7 +231,7 @@ async def test_light_service_turn(hass, caplog, mock_pymodbus):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
||||||
CONF_ADDRESS: 17,
|
CONF_ADDRESS: 18,
|
||||||
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||||
CONF_SCAN_INTERVAL: 0,
|
CONF_SCAN_INTERVAL: 0,
|
||||||
CONF_VERIFY: {},
|
CONF_VERIFY: {},
|
||||||
|
@ -245,7 +245,7 @@ async def test_switch_service_turn(hass, caplog, mock_pymodbus):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
CONF_NAME: f"{TEST_ENTITY_NAME}2",
|
||||||
CONF_ADDRESS: 17,
|
CONF_ADDRESS: 18,
|
||||||
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
CONF_WRITE_TYPE: CALL_TYPE_REGISTER_HOLDING,
|
||||||
CONF_SCAN_INTERVAL: 0,
|
CONF_SCAN_INTERVAL: 0,
|
||||||
CONF_VERIFY: {},
|
CONF_VERIFY: {},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user