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, MODBUS_DOMAIN as DOMAIN,
) )
from .modbus import async_modbus_setup from .modbus import async_modbus_setup
from .validators import ( from .validators import number_validator, scan_interval_validator, struct_validator
number_validator,
scan_interval_validator,
sensor_schema_validator,
)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -145,7 +141,7 @@ BASE_STRUCT_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
CALL_TYPE_REGISTER_INPUT, 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( vol.Optional(CONF_DATA_TYPE, default=DATA_TYPE_INT): vol.In(
[ [
DATA_TYPE_INT16, DATA_TYPE_INT16,
@ -289,12 +285,12 @@ MODBUS_SCHEMA = vol.Schema(
cv.ensure_list, [BINARY_SENSOR_SCHEMA] cv.ensure_list, [BINARY_SENSOR_SCHEMA]
), ),
vol.Optional(CONF_CLIMATES): vol.All( 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_COVERS): vol.All(cv.ensure_list, [COVERS_SCHEMA]),
vol.Optional(CONF_LIGHTS): vol.All(cv.ensure_list, [LIGHT_SCHEMA]), vol.Optional(CONF_LIGHTS): vol.All(cv.ensure_list, [LIGHT_SCHEMA]),
vol.Optional(CONF_SENSORS): vol.All( 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_SWITCHES): vol.All(cv.ensure_list, [SWITCH_SCHEMA]),
vol.Optional(CONF_FANS): vol.All(cv.ensure_list, [FAN_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_SLAVE = 1
DEFAULT_STRUCTURE_PREFIX = ">f" DEFAULT_STRUCTURE_PREFIX = ">f"
DEFAULT_STRUCT_FORMAT = { DEFAULT_STRUCT_FORMAT = {
DATA_TYPE_INT16: "h", DATA_TYPE_INT16: ["h", 1],
DATA_TYPE_INT32: "i", DATA_TYPE_INT32: ["i", 2],
DATA_TYPE_INT64: "q", DATA_TYPE_INT64: ["q", 4],
DATA_TYPE_UINT16: "H", DATA_TYPE_UINT16: ["H", 1],
DATA_TYPE_UINT32: "I", DATA_TYPE_UINT32: ["I", 2],
DATA_TYPE_UINT64: "Q", DATA_TYPE_UINT64: ["Q", 4],
DATA_TYPE_FLOAT16: "e", DATA_TYPE_FLOAT16: ["e", 1],
DATA_TYPE_FLOAT32: "f", DATA_TYPE_FLOAT32: ["f", 2],
DATA_TYPE_FLOAT64: "d", DATA_TYPE_FLOAT64: ["d", 4],
DATA_TYPE_STRING: "s", DATA_TYPE_STRING: ["s", 1],
} }
DEFAULT_TEMP_UNIT = "C" DEFAULT_TEMP_UNIT = "C"
MODBUS_DOMAIN = "modbus" MODBUS_DOMAIN = "modbus"

View File

@ -40,7 +40,7 @@ from .const import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
old_data_types = { OLD_DATA_TYPES = {
DATA_TYPE_INT: { DATA_TYPE_INT: {
1: DATA_TYPE_INT16, 1: DATA_TYPE_INT16,
2: DATA_TYPE_INT32, 2: DATA_TYPE_INT32,
@ -59,39 +59,41 @@ old_data_types = {
} }
def sensor_schema_validator(config): def struct_validator(config):
"""Sensor schema validator.""" """Sensor schema validator."""
data_type = config[CONF_DATA_TYPE] data_type = config[CONF_DATA_TYPE]
count = config[CONF_COUNT] count = config.get(CONF_COUNT, 1)
name = config[CONF_NAME] name = config[CONF_NAME]
structure = config.get(CONF_STRUCTURE) structure = config.get(CONF_STRUCTURE)
swap_type = config.get(CONF_SWAP) swap_type = config.get(CONF_SWAP)
if data_type in [DATA_TYPE_INT, DATA_TYPE_UINT, DATA_TYPE_FLOAT]: 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) _LOGGER.warning(error)
try: 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: 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: if config[CONF_DATA_TYPE] != DATA_TYPE_CUSTOM:
try: if structure:
structure = f">{DEFAULT_STRUCT_FORMAT[data_type]}" error = f"{name} structure: cannot be mixed with {data_type}"
except KeyError as exp: raise vol.Invalid(error)
raise vol.Invalid(f"Modbus error {data_type} unknown in {name}") from exp structure = f">{DEFAULT_STRUCT_FORMAT[data_type][0]}"
if CONF_COUNT not in config:
config[CONF_COUNT] = DEFAULT_STRUCT_FORMAT[data_type][1]
else: else:
if not structure: if not structure:
raise vol.Invalid( error = (
f"Error in sensor {config[CONF_NAME]}. The `{CONF_STRUCTURE}` field can not be empty " f"Error in sensor {name}. The `{CONF_STRUCTURE}` field can not be empty"
f"if the parameter `{CONF_DATA_TYPE}` is set to the `{DATA_TYPE_CUSTOM}`"
) )
raise vol.Invalid(error)
try: try:
size = struct.calcsize(structure) size = struct.calcsize(structure)
except struct.error as err: except struct.error as err:
raise vol.Invalid(f"Error in {name} structure: {str(err)}") from err raise vol.Invalid(f"Error in {name} structure: {str(err)}") from err
count = config.get(CONF_COUNT, 1)
bytecount = count * 2 bytecount = count * 2
if bytecount != size: if bytecount != size:
raise vol.Invalid( raise vol.Invalid(

View File

@ -55,7 +55,7 @@ from homeassistant.components.modbus.const import (
) )
from homeassistant.components.modbus.validators import ( from homeassistant.components.modbus.validators import (
number_validator, number_validator,
sensor_schema_validator, struct_validator,
) )
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import ( 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.""" """Test struct validator."""
try: try:
sensor_schema_validator(do_config) struct_validator(do_config)
except vol.Invalid: except vol.Invalid:
pytest.fail("Sensor_schema_validator unexpected exception") pytest.fail("struct_validator unexpected exception")
@pytest.mark.parametrize( @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.""" """Test struct validator."""
try: try:
sensor_schema_validator(do_config) struct_validator(do_config)
except vol.Invalid: except vol.Invalid:
return return
pytest.fail("Sensor_schema_validator missing exception") pytest.fail("struct_validator missing exception")
@pytest.mark.parametrize( @pytest.mark.parametrize(

View File

@ -174,7 +174,7 @@ async def test_config_sensor(hass, mock_modbus):
CONF_SWAP: CONF_SWAP_NONE, CONF_SWAP: CONF_SWAP_NONE,
CONF_STRUCTURE: "", 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",
), ),
( (
{ {