diff --git a/homeassistant/components/modbus/__init__.py b/homeassistant/components/modbus/__init__.py index f81a1200905..0f674d4d0df 100644 --- a/homeassistant/components/modbus/__init__.py +++ b/homeassistant/components/modbus/__init__.py @@ -136,7 +136,6 @@ from .validators import ( check_config, duplicate_fan_mode_validator, nan_validator, - number_validator, register_int_list_validator, struct_validator, ) @@ -187,8 +186,8 @@ BASE_STRUCT_SCHEMA = BASE_COMPONENT_SCHEMA.extend( ] ), vol.Optional(CONF_STRUCTURE): cv.string, - vol.Optional(CONF_SCALE, default=1): number_validator, - vol.Optional(CONF_OFFSET, default=0): number_validator, + vol.Optional(CONF_SCALE, default=1): cv.positive_float, + vol.Optional(CONF_OFFSET, default=0): vol.Coerce(float), vol.Optional(CONF_PRECISION): cv.positive_int, vol.Optional( CONF_SWAP, @@ -242,8 +241,8 @@ CLIMATE_SCHEMA = vol.All( { vol.Required(CONF_TARGET_TEMP): cv.positive_int, vol.Optional(CONF_TARGET_TEMP_WRITE_REGISTERS, default=False): cv.boolean, - vol.Optional(CONF_MAX_TEMP, default=35): number_validator, - vol.Optional(CONF_MIN_TEMP, default=5): number_validator, + vol.Optional(CONF_MAX_TEMP, default=35): cv.positive_float, + vol.Optional(CONF_MIN_TEMP, default=5): cv.positive_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_HVAC_ONOFF_REGISTER): cv.positive_int, @@ -343,10 +342,10 @@ SENSOR_SCHEMA = vol.All( vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Exclusive(CONF_VIRTUAL_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_MAX_VALUE): number_validator, + vol.Optional(CONF_MIN_VALUE): cv.positive_float, + vol.Optional(CONF_MAX_VALUE): cv.positive_float, vol.Optional(CONF_NAN_VALUE): nan_validator, - vol.Optional(CONF_ZERO_SUPPRESS): number_validator, + vol.Optional(CONF_ZERO_SUPPRESS): cv.positive_float, } ), ) diff --git a/homeassistant/components/modbus/base_platform.py b/homeassistant/components/modbus/base_platform.py index af9b83f8b85..877d33afbcc 100644 --- a/homeassistant/components/modbus/base_platform.py +++ b/homeassistant/components/modbus/base_platform.py @@ -182,12 +182,25 @@ class BaseStructPlatform(BasePlatform, RestoreEntity): self._data_type = config[CONF_DATA_TYPE] self._structure: str = config[CONF_STRUCTURE] 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._slave_count = config.get(CONF_SLAVE_COUNT, None) or config.get( CONF_VIRTUAL_COUNT, 0 ) 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]: """Do swap as needed.""" @@ -227,7 +240,7 @@ class BaseStructPlatform(BasePlatform, RestoreEntity): return str(self._max_value) if self._zero_suppress is not None and abs(val) <= self._zero_suppress: return "0" - if self._precision == 0: + if self._precision == 0 or self._value_is_int: return str(int(round(val, 0))) return f"{float(val):.{self._precision}f}" diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index c015d117b13..4f2a1d6dc76 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -125,7 +125,10 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreSensor, SensorEntity): if self._coordinator: if result: 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._coordinator.async_set_updated_data(result_array) diff --git a/homeassistant/components/modbus/validators.py b/homeassistant/components/modbus/validators.py index e8ce35e834f..76d8e270ffe 100644 --- a/homeassistant/components/modbus/validators.py +++ b/homeassistant/components/modbus/validators.py @@ -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: """Convert nan string to number (can be hex string or int).""" if isinstance(value, int): diff --git a/tests/components/modbus/test_init.py b/tests/components/modbus/test_init.py index 24ae8d0ebfc..3c932a24afb 100644 --- a/tests/components/modbus/test_init.py +++ b/tests/components/modbus/test_init.py @@ -83,7 +83,6 @@ from homeassistant.components.modbus.validators import ( duplicate_fan_mode_validator, duplicate_modbus_validator, nan_validator, - number_validator, register_int_list_validator, struct_validator, ) @@ -157,28 +156,6 @@ async def test_register_int_list_validator() -> None: 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: """Test number validator.""" diff --git a/tests/components/modbus/test_sensor.py b/tests/components/modbus/test_sensor.py index c9e943b06a7..7c58290b143 100644 --- a/tests/components/modbus/test_sensor.py +++ b/tests/components/modbus/test_sensor.py @@ -357,7 +357,7 @@ async def test_config_wrong_struct_sensor( }, [7], False, - "34.0000", + "34", ), ( { @@ -379,7 +379,7 @@ async def test_config_wrong_struct_sensor( }, [9], False, - "18.5", + "18", ), ( { @@ -390,7 +390,7 @@ async def test_config_wrong_struct_sensor( }, [1], False, - "2.40", + "2", ), ( { @@ -401,7 +401,7 @@ async def test_config_wrong_struct_sensor( }, [2], False, - "-8.3", + "-8", ), ( { @@ -445,7 +445,7 @@ async def test_config_wrong_struct_sensor( }, [0x89AB, 0xCDEF, 0x0123, 0x4567], False, - "9920249030613615975", + "9920249030613616640", ), ( { @@ -456,7 +456,7 @@ async def test_config_wrong_struct_sensor( }, [0x0123, 0x4567, 0x89AB, 0xCDEF], False, - "163971058432973793", + "163971058432973792", ), ( { @@ -676,7 +676,7 @@ async def test_config_wrong_struct_sensor( }, [0x00AB, 0xCDEF], False, - "112593.75", + "112594", ), ( { @@ -686,7 +686,7 @@ async def test_config_wrong_struct_sensor( }, [0x00AB, 0xCDEF], 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]), ], 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]), ], False, - ["34899771392", "0"], + ["34899771392.0", "0.0"], ), ( { @@ -937,7 +937,7 @@ async def test_virtual_sensor( }, [0x0102, 0x0304, 0x0506, 0x0708], False, - [str(0x0708050603040102)], + [str(0x0708050603040100)], ), ( { @@ -970,7 +970,7 @@ async def test_virtual_sensor( }, [0x0102, 0x0304, 0x0506, 0x0708, 0x0901, 0x0902, 0x0903, 0x0904], False, - [str(0x0708050603040102), str(0x0904090309020901)], + [str(0x0708050603040100), str(0x0904090309020900)], ), ( { @@ -1035,10 +1035,10 @@ async def test_virtual_sensor( ], False, [ - str(0x0604060306020601), - str(0x0704070307020701), - str(0x0804080308020801), - str(0x0904090309020901), + str(0x0604060306020600), + str(0x0704070307020700), + str(0x0804080308020800), + str(0x0904090309020900), ], ), ], @@ -1202,7 +1202,7 @@ async def test_unpack_ok(hass: HomeAssistant, mock_do_cycle, expected) -> None: 0x0000, 0x000A, ], - "0,10", + "0,10.00", ), ( {