Replace modbus number_validator by HA standard (#108939)

This commit is contained in:
jan iversen 2024-01-27 16:39:33 +01:00 committed by GitHub
parent 858fb1fa37
commit 3cc5ffaa4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 43 additions and 68 deletions

View File

@ -136,7 +136,6 @@ from .validators import (
check_config, check_config,
duplicate_fan_mode_validator, duplicate_fan_mode_validator,
nan_validator, nan_validator,
number_validator,
register_int_list_validator, register_int_list_validator,
struct_validator, struct_validator,
) )
@ -187,8 +186,8 @@ BASE_STRUCT_SCHEMA = BASE_COMPONENT_SCHEMA.extend(
] ]
), ),
vol.Optional(CONF_STRUCTURE): cv.string, vol.Optional(CONF_STRUCTURE): cv.string,
vol.Optional(CONF_SCALE, default=1): number_validator, vol.Optional(CONF_SCALE, default=1): cv.positive_float,
vol.Optional(CONF_OFFSET, default=0): number_validator, vol.Optional(CONF_OFFSET, default=0): vol.Coerce(float),
vol.Optional(CONF_PRECISION): cv.positive_int, vol.Optional(CONF_PRECISION): cv.positive_int,
vol.Optional( vol.Optional(
CONF_SWAP, CONF_SWAP,
@ -242,8 +241,8 @@ CLIMATE_SCHEMA = vol.All(
{ {
vol.Required(CONF_TARGET_TEMP): cv.positive_int, vol.Required(CONF_TARGET_TEMP): cv.positive_int,
vol.Optional(CONF_TARGET_TEMP_WRITE_REGISTERS, default=False): cv.boolean, vol.Optional(CONF_TARGET_TEMP_WRITE_REGISTERS, default=False): cv.boolean,
vol.Optional(CONF_MAX_TEMP, default=35): number_validator, vol.Optional(CONF_MAX_TEMP, default=35): cv.positive_float,
vol.Optional(CONF_MIN_TEMP, default=5): number_validator, vol.Optional(CONF_MIN_TEMP, default=5): cv.positive_float,
vol.Optional(CONF_STEP, default=0.5): vol.Coerce(float), vol.Optional(CONF_STEP, default=0.5): vol.Coerce(float),
vol.Optional(CONF_TEMPERATURE_UNIT, default=DEFAULT_TEMP_UNIT): cv.string, vol.Optional(CONF_TEMPERATURE_UNIT, default=DEFAULT_TEMP_UNIT): cv.string,
vol.Optional(CONF_HVAC_ONOFF_REGISTER): cv.positive_int, vol.Optional(CONF_HVAC_ONOFF_REGISTER): cv.positive_int,
@ -343,10 +342,10 @@ SENSOR_SCHEMA = vol.All(
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
vol.Exclusive(CONF_VIRTUAL_COUNT, "vir_sen_count"): cv.positive_int, vol.Exclusive(CONF_VIRTUAL_COUNT, "vir_sen_count"): cv.positive_int,
vol.Exclusive(CONF_SLAVE_COUNT, "vir_sen_count"): cv.positive_int, vol.Exclusive(CONF_SLAVE_COUNT, "vir_sen_count"): cv.positive_int,
vol.Optional(CONF_MIN_VALUE): number_validator, vol.Optional(CONF_MIN_VALUE): cv.positive_float,
vol.Optional(CONF_MAX_VALUE): number_validator, vol.Optional(CONF_MAX_VALUE): cv.positive_float,
vol.Optional(CONF_NAN_VALUE): nan_validator, vol.Optional(CONF_NAN_VALUE): nan_validator,
vol.Optional(CONF_ZERO_SUPPRESS): number_validator, vol.Optional(CONF_ZERO_SUPPRESS): cv.positive_float,
} }
), ),
) )

View File

@ -182,12 +182,25 @@ class BaseStructPlatform(BasePlatform, RestoreEntity):
self._data_type = config[CONF_DATA_TYPE] self._data_type = config[CONF_DATA_TYPE]
self._structure: str = config[CONF_STRUCTURE] self._structure: str = config[CONF_STRUCTURE]
self._scale = config[CONF_SCALE] self._scale = config[CONF_SCALE]
self._precision = config.get(CONF_PRECISION, 2 if self._scale < 1 else 0) self._precision = config.get(CONF_PRECISION, 2)
self._offset = config[CONF_OFFSET] self._offset = config[CONF_OFFSET]
self._slave_count = config.get(CONF_SLAVE_COUNT, None) or config.get( self._slave_count = config.get(CONF_SLAVE_COUNT, None) or config.get(
CONF_VIRTUAL_COUNT, 0 CONF_VIRTUAL_COUNT, 0
) )
self._slave_size = self._count = config[CONF_COUNT] self._slave_size = self._count = config[CONF_COUNT]
self._value_is_int: bool = self._data_type in (
DataType.INT16,
DataType.INT32,
DataType.INT64,
DataType.UINT16,
DataType.UINT32,
DataType.UINT64,
)
if self._value_is_int:
if self._min_value:
self._min_value = round(self._min_value)
if self._max_value:
self._max_value = round(self._max_value)
def _swap_registers(self, registers: list[int], slave_count: int) -> list[int]: def _swap_registers(self, registers: list[int], slave_count: int) -> list[int]:
"""Do swap as needed.""" """Do swap as needed."""
@ -227,7 +240,7 @@ class BaseStructPlatform(BasePlatform, RestoreEntity):
return str(self._max_value) return str(self._max_value)
if self._zero_suppress is not None and abs(val) <= self._zero_suppress: if self._zero_suppress is not None and abs(val) <= self._zero_suppress:
return "0" return "0"
if self._precision == 0: if self._precision == 0 or self._value_is_int:
return str(int(round(val, 0))) return str(int(round(val, 0)))
return f"{float(val):.{self._precision}f}" return f"{float(val):.{self._precision}f}"

View File

@ -125,7 +125,10 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreSensor, SensorEntity):
if self._coordinator: if self._coordinator:
if result: if result:
result_array = list( result_array = list(
map(float if self._precision else int, result.split(",")) map(
float if not self._value_is_int else int,
result.split(","),
)
) )
self._attr_native_value = result_array[0] self._attr_native_value = result_array[0]
self._coordinator.async_set_updated_data(result_array) self._coordinator.async_set_updated_data(result_array)

View File

@ -172,23 +172,6 @@ def struct_validator(config: dict[str, Any]) -> dict[str, Any]:
} }
def number_validator(value: Any) -> int | float:
"""Coerce a value to number without losing precision."""
if isinstance(value, int):
return value
if isinstance(value, float):
return value
try:
return int(value)
except (TypeError, ValueError):
pass
try:
return float(value)
except (TypeError, ValueError) as err:
raise vol.Invalid(f"invalid number {value}") from err
def nan_validator(value: Any) -> int: def nan_validator(value: Any) -> int:
"""Convert nan string to number (can be hex string or int).""" """Convert nan string to number (can be hex string or int)."""
if isinstance(value, int): if isinstance(value, int):

View File

@ -83,7 +83,6 @@ from homeassistant.components.modbus.validators import (
duplicate_fan_mode_validator, duplicate_fan_mode_validator,
duplicate_modbus_validator, duplicate_modbus_validator,
nan_validator, nan_validator,
number_validator,
register_int_list_validator, register_int_list_validator,
struct_validator, struct_validator,
) )
@ -157,28 +156,6 @@ async def test_register_int_list_validator() -> None:
register_int_list_validator(["aq"]) register_int_list_validator(["aq"])
async def test_number_validator() -> None:
"""Test number validator."""
for value, value_type in (
(15, int),
(15.1, float),
("15", int),
("15.1", float),
(-15, int),
(-15.1, float),
("-15", int),
("-15.1", float),
):
assert isinstance(number_validator(value), value_type)
try:
number_validator("x15.1")
except vol.Invalid:
return
pytest.fail("Number_validator not throwing exception")
async def test_nan_validator() -> None: async def test_nan_validator() -> None:
"""Test number validator.""" """Test number validator."""

View File

@ -357,7 +357,7 @@ async def test_config_wrong_struct_sensor(
}, },
[7], [7],
False, False,
"34.0000", "34",
), ),
( (
{ {
@ -379,7 +379,7 @@ async def test_config_wrong_struct_sensor(
}, },
[9], [9],
False, False,
"18.5", "18",
), ),
( (
{ {
@ -390,7 +390,7 @@ async def test_config_wrong_struct_sensor(
}, },
[1], [1],
False, False,
"2.40", "2",
), ),
( (
{ {
@ -401,7 +401,7 @@ async def test_config_wrong_struct_sensor(
}, },
[2], [2],
False, False,
"-8.3", "-8",
), ),
( (
{ {
@ -445,7 +445,7 @@ async def test_config_wrong_struct_sensor(
}, },
[0x89AB, 0xCDEF, 0x0123, 0x4567], [0x89AB, 0xCDEF, 0x0123, 0x4567],
False, False,
"9920249030613615975", "9920249030613616640",
), ),
( (
{ {
@ -456,7 +456,7 @@ async def test_config_wrong_struct_sensor(
}, },
[0x0123, 0x4567, 0x89AB, 0xCDEF], [0x0123, 0x4567, 0x89AB, 0xCDEF],
False, False,
"163971058432973793", "163971058432973792",
), ),
( (
{ {
@ -676,7 +676,7 @@ async def test_config_wrong_struct_sensor(
}, },
[0x00AB, 0xCDEF], [0x00AB, 0xCDEF],
False, False,
"112593.75", "112594",
), ),
( (
{ {
@ -686,7 +686,7 @@ async def test_config_wrong_struct_sensor(
}, },
[0x00AB, 0xCDEF], [0x00AB, 0xCDEF],
False, False,
"112593.75", "112594",
), ),
], ],
) )
@ -727,7 +727,7 @@ async def test_all_sensor(hass: HomeAssistant, mock_do_cycle, expected) -> None:
int.from_bytes(struct.pack(">f", float("nan"))[2:4]), int.from_bytes(struct.pack(">f", float("nan"))[2:4]),
], ],
False, False,
["34899771392", "0"], ["34899771392.0", "0.0"],
), ),
( (
{ {
@ -742,7 +742,7 @@ async def test_all_sensor(hass: HomeAssistant, mock_do_cycle, expected) -> None:
int.from_bytes(struct.pack(">f", float("nan"))[2:4]), int.from_bytes(struct.pack(">f", float("nan"))[2:4]),
], ],
False, False,
["34899771392", "0"], ["34899771392.0", "0.0"],
), ),
( (
{ {
@ -937,7 +937,7 @@ async def test_virtual_sensor(
}, },
[0x0102, 0x0304, 0x0506, 0x0708], [0x0102, 0x0304, 0x0506, 0x0708],
False, False,
[str(0x0708050603040102)], [str(0x0708050603040100)],
), ),
( (
{ {
@ -970,7 +970,7 @@ async def test_virtual_sensor(
}, },
[0x0102, 0x0304, 0x0506, 0x0708, 0x0901, 0x0902, 0x0903, 0x0904], [0x0102, 0x0304, 0x0506, 0x0708, 0x0901, 0x0902, 0x0903, 0x0904],
False, False,
[str(0x0708050603040102), str(0x0904090309020901)], [str(0x0708050603040100), str(0x0904090309020900)],
), ),
( (
{ {
@ -1035,10 +1035,10 @@ async def test_virtual_sensor(
], ],
False, False,
[ [
str(0x0604060306020601), str(0x0604060306020600),
str(0x0704070307020701), str(0x0704070307020700),
str(0x0804080308020801), str(0x0804080308020800),
str(0x0904090309020901), str(0x0904090309020900),
], ],
), ),
], ],
@ -1202,7 +1202,7 @@ async def test_unpack_ok(hass: HomeAssistant, mock_do_cycle, expected) -> None:
0x0000, 0x0000,
0x000A, 0x000A,
], ],
"0,10", "0,10.00",
), ),
( (
{ {