Improve custom datatype parsing in Modbus sensor and climate (#42354)
parent
5e3941badb
commit
d518db1c95
|
@ -547,6 +547,7 @@ omit =
|
|||
homeassistant/components/modbus/climate.py
|
||||
homeassistant/components/modbus/cover.py
|
||||
homeassistant/components/modbus/switch.py
|
||||
homeassistant/components/modbus/sensor.py
|
||||
homeassistant/components/modem_callerid/sensor.py
|
||||
homeassistant/components/motion_blinds/__init__.py
|
||||
homeassistant/components/motion_blinds/const.py
|
||||
|
|
|
@ -255,7 +255,15 @@ class ModbusThermostat(ClimateEntity):
|
|||
byte_string = b"".join(
|
||||
[x.to_bytes(2, byteorder="big") for x in result.registers]
|
||||
)
|
||||
val = struct.unpack(self._structure, byte_string)[0]
|
||||
val = struct.unpack(self._structure, byte_string)
|
||||
if len(val) != 1 or not isinstance(val[0], (float, int)):
|
||||
_LOGGER.error(
|
||||
"Unable to parse result as a single int or float value; adjust your configuration. Result: %s",
|
||||
str(val),
|
||||
)
|
||||
return -1
|
||||
|
||||
val = val[0]
|
||||
register_value = format(
|
||||
(self._scale * val) + self._offset, f".{self._precision}f"
|
||||
)
|
||||
|
|
|
@ -250,16 +250,32 @@ class ModbusRegisterSensor(RestoreEntity):
|
|||
registers.reverse()
|
||||
|
||||
byte_string = b"".join([x.to_bytes(2, byteorder="big") for x in registers])
|
||||
if self._data_type != DATA_TYPE_STRING:
|
||||
val = struct.unpack(self._structure, byte_string)[0]
|
||||
val = self._scale * val + self._offset
|
||||
if isinstance(val, int):
|
||||
self._value = str(val)
|
||||
if self._precision > 0:
|
||||
self._value += "." + "0" * self._precision
|
||||
else:
|
||||
self._value = f"{val:.{self._precision}f}"
|
||||
else:
|
||||
if self._data_type == DATA_TYPE_STRING:
|
||||
self._value = byte_string.decode()
|
||||
else:
|
||||
val = struct.unpack(self._structure, byte_string)
|
||||
|
||||
# Issue: https://github.com/home-assistant/core/issues/41944
|
||||
# If unpack() returns a tuple greater than 1, don't try to process the value.
|
||||
# Instead, return the values of unpack(...) separated by commas.
|
||||
if len(val) > 1:
|
||||
self._value = ",".join(map(str, val))
|
||||
else:
|
||||
val = val[0]
|
||||
|
||||
# Apply scale and precision to floats and ints
|
||||
if isinstance(val, (float, int)):
|
||||
val = self._scale * val + self._offset
|
||||
|
||||
# We could convert int to float, and the code would still work; however
|
||||
# we lose some precision, and unit tests will fail. Therefore, we do
|
||||
# the conversion only when it's absolutely necessary.
|
||||
if isinstance(val, int) and self._precision == 0:
|
||||
self._value = str(val)
|
||||
else:
|
||||
self._value = f"{float(val):.{self._precision}f}"
|
||||
else:
|
||||
# Don't process remaining datatypes (bytes and booleans)
|
||||
self._value = str(val)
|
||||
|
||||
self._available = True
|
||||
|
|
Loading…
Reference in New Issue