Calculate count automatically in modbus platforms (#53116)

This commit is contained in:
jan iversen 2021-07-21 07:49:54 +02:00 committed by GitHub
parent 2e2b340b1e
commit 7306503756
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 41 deletions

View file

@ -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]),

View file

@ -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"

View file

@ -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(

View file

@ -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(

View file

@ -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",
),
(
{