Report modbus buffer too small or too big to unpack (#57838)
This commit is contained in:
parent
38586d2cf1
commit
cca7da77ad
5 changed files with 54 additions and 4 deletions
|
@ -160,7 +160,7 @@ class BaseStructPlatform(BasePlatform, RestoreEntity):
|
||||||
registers.reverse()
|
registers.reverse()
|
||||||
return registers
|
return registers
|
||||||
|
|
||||||
def unpack_structure_result(self, registers: list[int]) -> str:
|
def unpack_structure_result(self, registers: list[int]) -> str | None:
|
||||||
"""Convert registers to proper result."""
|
"""Convert registers to proper result."""
|
||||||
|
|
||||||
registers = self._swap_registers(registers)
|
registers = self._swap_registers(registers)
|
||||||
|
@ -168,7 +168,13 @@ class BaseStructPlatform(BasePlatform, RestoreEntity):
|
||||||
if self._data_type == DataType.STRING:
|
if self._data_type == DataType.STRING:
|
||||||
return byte_string.decode()
|
return byte_string.decode()
|
||||||
|
|
||||||
val = struct.unpack(self._structure, byte_string)
|
try:
|
||||||
|
val = struct.unpack(self._structure, byte_string)
|
||||||
|
except struct.error as err:
|
||||||
|
recv_size = len(registers) * 2
|
||||||
|
msg = f"Received {recv_size} bytes, unpack error {err}"
|
||||||
|
_LOGGER.error(msg)
|
||||||
|
return None
|
||||||
# Issue: https://github.com/home-assistant/core/issues/41944
|
# Issue: https://github.com/home-assistant/core/issues/41944
|
||||||
# If unpack() returns a tuple greater than 1, don't try to process the value.
|
# If unpack() returns a tuple greater than 1, don't try to process the value.
|
||||||
# Instead, return the values of unpack(...) separated by commas.
|
# Instead, return the values of unpack(...) separated by commas.
|
||||||
|
|
|
@ -166,7 +166,8 @@ class ModbusThermostat(BaseStructPlatform, RestoreEntity, ClimateEntity):
|
||||||
|
|
||||||
self._lazy_errors = self._lazy_error_count
|
self._lazy_errors = self._lazy_error_count
|
||||||
self._value = self.unpack_structure_result(result.registers)
|
self._value = self.unpack_structure_result(result.registers)
|
||||||
self._attr_available = True
|
|
||||||
if not self._value:
|
if not self._value:
|
||||||
|
self._attr_available = False
|
||||||
return None
|
return None
|
||||||
|
self._attr_available = True
|
||||||
return float(self._value)
|
return float(self._value)
|
||||||
|
|
|
@ -74,6 +74,9 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreEntity, SensorEntity):
|
||||||
return
|
return
|
||||||
|
|
||||||
self._attr_native_value = self.unpack_structure_result(result.registers)
|
self._attr_native_value = self.unpack_structure_result(result.registers)
|
||||||
|
if self._attr_native_value is None:
|
||||||
|
self._attr_available = False
|
||||||
|
else:
|
||||||
|
self._attr_available = True
|
||||||
self._lazy_errors = self._lazy_error_count
|
self._lazy_errors = self._lazy_error_count
|
||||||
self._attr_available = True
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
|
@ -94,11 +94,13 @@ async def test_temperature_climate(hass, expected, mock_do_cycle):
|
||||||
{
|
{
|
||||||
CONF_CLIMATES: [
|
CONF_CLIMATES: [
|
||||||
{
|
{
|
||||||
|
CONF_COUNT: 2,
|
||||||
CONF_NAME: TEST_ENTITY_NAME,
|
CONF_NAME: TEST_ENTITY_NAME,
|
||||||
CONF_TARGET_TEMP: 117,
|
CONF_TARGET_TEMP: 117,
|
||||||
CONF_ADDRESS: 117,
|
CONF_ADDRESS: 117,
|
||||||
CONF_SLAVE: 10,
|
CONF_SLAVE: 10,
|
||||||
CONF_SCAN_INTERVAL: 0,
|
CONF_SCAN_INTERVAL: 0,
|
||||||
|
CONF_DATA_TYPE: DataType.INT32,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -559,6 +559,44 @@ async def test_all_sensor(hass, mock_do_cycle, expected):
|
||||||
assert hass.states.get(ENTITY_ID).state == expected
|
assert hass.states.get(ENTITY_ID).state == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"do_config",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
CONF_SENSORS: [
|
||||||
|
{
|
||||||
|
CONF_NAME: TEST_ENTITY_NAME,
|
||||||
|
CONF_ADDRESS: 51,
|
||||||
|
CONF_SCAN_INTERVAL: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"config_addon,register_words",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{
|
||||||
|
CONF_COUNT: 1,
|
||||||
|
CONF_DATA_TYPE: DataType.INT16,
|
||||||
|
},
|
||||||
|
[7, 9],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
CONF_COUNT: 2,
|
||||||
|
CONF_DATA_TYPE: DataType.INT32,
|
||||||
|
},
|
||||||
|
[7],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_wrong_unpack(hass, mock_do_cycle):
|
||||||
|
"""Run test for sensor."""
|
||||||
|
assert hass.states.get(ENTITY_ID).state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"do_config",
|
"do_config",
|
||||||
[
|
[
|
||||||
|
|
Loading…
Add table
Reference in a new issue