Calculate count automatically in modbus platforms (#53116)
This commit is contained in:
parent
2e2b340b1e
commit
7306503756
5 changed files with 39 additions and 41 deletions
|
@ -114,11 +114,7 @@ from .const import (
|
|||
MODBUS_DOMAIN as DOMAIN,
|
||||
)
|
||||
from .modbus import async_modbus_setup
|
||||
from .validators import (
|
||||
number_validator,
|
||||
scan_interval_validator,
|
||||
sensor_schema_validator,
|
||||
)
|
||||
from .validators import number_validator, scan_interval_validator, struct_validator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -145,7 +141,7 @@ BASE_STRUCT_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
|
|||
CALL_TYPE_REGISTER_INPUT,
|
||||
]
|
||||
),
|
||||
vol.Optional(CONF_COUNT, default=1): cv.positive_int,
|
||||
vol.Optional(CONF_COUNT): cv.positive_int,
|
||||
vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_INT): vol.In(
|
||||
[
|
||||
DATA_TYPE_INT16,
|
||||
|
@ -289,12 +285,12 @@ MODBUS_SCHEMA = vol.Schema(
|
|||
cv.ensure_list, [BINARY_SENSOR_SCHEMA]
|
||||
),
|
||||
vol.Optional(CONF_CLIMATES): vol.All(
|
||||
cv.ensure_list, [vol.All(CLIMATE_SCHEMA, sensor_schema_validator)]
|
||||
cv.ensure_list, [vol.All(CLIMATE_SCHEMA, struct_validator)]
|
||||
),
|
||||
vol.Optional(CONF_COVERS): vol.All(cv.ensure_list, [COVERS_SCHEMA]),
|
||||
vol.Optional(CONF_LIGHTS): vol.All(cv.ensure_list, [LIGHT_SCHEMA]),
|
||||
vol.Optional(CONF_SENSORS): vol.All(
|
||||
cv.ensure_list, [vol.All(SENSOR_SCHEMA, sensor_schema_validator)]
|
||||
cv.ensure_list, [vol.All(SENSOR_SCHEMA, struct_validator)]
|
||||
),
|
||||
vol.Optional(CONF_SWITCHES): vol.All(cv.ensure_list, [SWITCH_SCHEMA]),
|
||||
vol.Optional(CONF_FANS): vol.All(cv.ensure_list, [FAN_SCHEMA]),
|
||||
|
|
|
@ -111,16 +111,16 @@ DEFAULT_SCAN_INTERVAL = 15 # seconds
|
|||
DEFAULT_SLAVE = 1
|
||||
DEFAULT_STRUCTURE_PREFIX = ">f"
|
||||
DEFAULT_STRUCT_FORMAT = {
|
||||
DATA_TYPE_INT16: "h",
|
||||
DATA_TYPE_INT32: "i",
|
||||
DATA_TYPE_INT64: "q",
|
||||
DATA_TYPE_UINT16: "H",
|
||||
DATA_TYPE_UINT32: "I",
|
||||
DATA_TYPE_UINT64: "Q",
|
||||
DATA_TYPE_FLOAT16: "e",
|
||||
DATA_TYPE_FLOAT32: "f",
|
||||
DATA_TYPE_FLOAT64: "d",
|
||||
DATA_TYPE_STRING: "s",
|
||||
DATA_TYPE_INT16: ["h", 1],
|
||||
DATA_TYPE_INT32: ["i", 2],
|
||||
DATA_TYPE_INT64: ["q", 4],
|
||||
DATA_TYPE_UINT16: ["H", 1],
|
||||
DATA_TYPE_UINT32: ["I", 2],
|
||||
DATA_TYPE_UINT64: ["Q", 4],
|
||||
DATA_TYPE_FLOAT16: ["e", 1],
|
||||
DATA_TYPE_FLOAT32: ["f", 2],
|
||||
DATA_TYPE_FLOAT64: ["d", 4],
|
||||
DATA_TYPE_STRING: ["s", 1],
|
||||
}
|
||||
DEFAULT_TEMP_UNIT = "C"
|
||||
MODBUS_DOMAIN = "modbus"
|
||||
|
|
|
@ -40,7 +40,7 @@ from .const import (
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
old_data_types = {
|
||||
OLD_DATA_TYPES = {
|
||||
DATA_TYPE_INT: {
|
||||
1: DATA_TYPE_INT16,
|
||||
2: DATA_TYPE_INT32,
|
||||
|
@ -59,39 +59,41 @@ old_data_types = {
|
|||
}
|
||||
|
||||
|
||||
def sensor_schema_validator(config):
|
||||
def struct_validator(config):
|
||||
"""Sensor schema validator."""
|
||||
|
||||
data_type = config[CONF_DATA_TYPE]
|
||||
count = config[CONF_COUNT]
|
||||
count = config.get(CONF_COUNT, 1)
|
||||
name = config[CONF_NAME]
|
||||
structure = config.get(CONF_STRUCTURE)
|
||||
swap_type = config.get(CONF_SWAP)
|
||||
if data_type in [DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT]:
|
||||
error = f"{name} {name} with {data_type} is not valid, trying to convert"
|
||||
error = f"{name} with {data_type} is not valid, trying to convert"
|
||||
_LOGGER.warning(error)
|
||||
try:
|
||||
data_type = old_data_types[data_type][count]
|
||||
data_type = OLD_DATA_TYPES[data_type][config.get(CONF_COUNT, 1)]
|
||||
except KeyError as exp:
|
||||
raise vol.Invalid("cannot convert automatically") from exp
|
||||
|
||||
error = f"{name} cannot convert automatically {data_type}"
|
||||
raise vol.Invalid(error) from exp
|
||||
if config[CONF_DATA_TYPE] != DATA_TYPE_CUSTOM:
|
||||
try:
|
||||
structure = f">{DEFAULT_STRUCT_FORMAT[data_type]}"
|
||||
except KeyError as exp:
|
||||
raise vol.Invalid(f"Modbus error {data_type} unknown in {name}") from exp
|
||||
if structure:
|
||||
error = f"{name} structure: cannot be mixed with {data_type}"
|
||||
raise vol.Invalid(error)
|
||||
structure = f">{DEFAULT_STRUCT_FORMAT[data_type][0]}"
|
||||
if CONF_COUNT not in config:
|
||||
config[CONF_COUNT] = DEFAULT_STRUCT_FORMAT[data_type][1]
|
||||
else:
|
||||
if not structure:
|
||||
raise vol.Invalid(
|
||||
f"Error in sensor {config[CONF_NAME]}. The `{CONF_STRUCTURE}` field can not be empty "
|
||||
f"if the parameter `{CONF_DATA_TYPE}` is set to the `{DATA_TYPE_CUSTOM}`"
|
||||
error = (
|
||||
f"Error in sensor {name}. The `{CONF_STRUCTURE}` field can not be empty"
|
||||
)
|
||||
|
||||
raise vol.Invalid(error)
|
||||
try:
|
||||
size = struct.calcsize(structure)
|
||||
except struct.error as err:
|
||||
raise vol.Invalid(f"Error in {name} structure: {str(err)}") from err
|
||||
|
||||
count = config.get(CONF_COUNT, 1)
|
||||
bytecount = count * 2
|
||||
if bytecount != size:
|
||||
raise vol.Invalid(
|
||||
|
|
|
@ -55,7 +55,7 @@ from homeassistant.components.modbus.const import (
|
|||
)
|
||||
from homeassistant.components.modbus.validators import (
|
||||
number_validator,
|
||||
sensor_schema_validator,
|
||||
struct_validator,
|
||||
)
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.const import (
|
||||
|
@ -144,12 +144,12 @@ async def test_number_validator():
|
|||
},
|
||||
],
|
||||
)
|
||||
async def test_ok_sensor_schema_validator(do_config):
|
||||
async def test_ok_struct_validator(do_config):
|
||||
"""Test struct validator."""
|
||||
try:
|
||||
sensor_schema_validator(do_config)
|
||||
struct_validator(do_config)
|
||||
except vol.Invalid:
|
||||
pytest.fail("Sensor_schema_validator unexpected exception")
|
||||
pytest.fail("struct_validator unexpected exception")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -186,13 +186,13 @@ async def test_ok_sensor_schema_validator(do_config):
|
|||
},
|
||||
],
|
||||
)
|
||||
async def test_exception_sensor_schema_validator(do_config):
|
||||
async def test_exception_struct_validator(do_config):
|
||||
"""Test struct validator."""
|
||||
try:
|
||||
sensor_schema_validator(do_config)
|
||||
struct_validator(do_config)
|
||||
except vol.Invalid:
|
||||
return
|
||||
pytest.fail("Sensor_schema_validator missing exception")
|
||||
pytest.fail("struct_validator missing exception")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
@ -174,7 +174,7 @@ async def test_config_sensor(hass, mock_modbus):
|
|||
CONF_SWAP: CONF_SWAP_NONE,
|
||||
CONF_STRUCTURE: "",
|
||||
},
|
||||
"Error in sensor test_sensor. The `structure` field can not be empty if the parameter `data_type` is set to the `custom`",
|
||||
"Error in sensor test_sensor. The `structure` field can not be empty",
|
||||
),
|
||||
(
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue