From a053142601c2acf45845ed390ea5c465d6d93d00 Mon Sep 17 00:00:00 2001 From: jan iversen Date: Mon, 1 Sep 2025 11:48:19 +0200 Subject: [PATCH] modbus: Do not modify registers (return wrong data). (#151131) --- homeassistant/components/modbus/entity.py | 5 ++- tests/components/modbus/test_sensor.py | 40 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/modbus/entity.py b/homeassistant/components/modbus/entity.py index 180495bd226a..d6101681d3f1 100644 --- a/homeassistant/components/modbus/entity.py +++ b/homeassistant/components/modbus/entity.py @@ -4,6 +4,7 @@ from __future__ import annotations from abc import abstractmethod from collections.abc import Callable +import copy from datetime import datetime, timedelta import struct from typing import Any, cast @@ -280,7 +281,9 @@ class BaseStructPlatform(BasePlatform, RestoreEntity): """Convert registers to proper result.""" if self._swap: - registers = self._swap_registers(registers, self._slave_count) + registers = self._swap_registers( + copy.deepcopy(registers), self._slave_count + ) byte_string = b"".join([x.to_bytes(2, byteorder="big") for x in registers]) if self._data_type == DataType.STRING: return byte_string.decode() diff --git a/tests/components/modbus/test_sensor.py b/tests/components/modbus/test_sensor.py index 4910b4df0654..868e8a8baada 100644 --- a/tests/components/modbus/test_sensor.py +++ b/tests/components/modbus/test_sensor.py @@ -1357,6 +1357,46 @@ async def test_wrap_sensor(hass: HomeAssistant, mock_do_cycle, expected) -> None assert hass.states.get(ENTITY_ID).state == expected +@pytest.mark.parametrize( + "do_config", + [ + { + CONF_SENSORS: [ + { + CONF_NAME: TEST_ENTITY_NAME, + CONF_ADDRESS: 201, + }, + ], + }, + ], +) +@pytest.mark.parametrize( + ("config_addon", "register_words", "expected"), + [ + ( + { + CONF_SWAP: CONF_SWAP_WORD, + CONF_DATA_TYPE: DataType.UINT32, + }, + [0x0102, 0x0304], + "50594050", + ), + ], +) +async def test_wrap_regs_ok_sensor( + hass: HomeAssistant, mock_modbus_ha, mock_do_cycle, expected +) -> None: + """Run test for sensor struct.""" + assert hass.states.get(ENTITY_ID).state == expected + await hass.services.async_call( + HOMEASSISTANT_DOMAIN, + SERVICE_UPDATE_ENTITY, + {ATTR_ENTITY_ID: ENTITY_ID}, + blocking=True, + ) + assert hass.states.get(ENTITY_ID).state == expected + + @pytest.fixture(name="mock_restore") async def mock_restore(hass: HomeAssistant) -> None: """Mock restore cache."""