Package: pystiebeleltron Version: 0.2.0-1 Severity: normal Tags: patch pending
Dear maintainer, I've prepared an NMU for pystiebeleltron (versioned as 0.2.0-1.1) and uploaded it to DELAYED/7. Please feel free to tell me if I should cancel it. This fixes an FTBFS introduced by the new version of pymodbus that I recently uploaded, sorry for the disturbance. I've also created an MR here: https://salsa.debian.org/homeassistant-team/deps/pystiebeleltron/-/merge_requests/1 to merge these changes in the packaging repository. Regards. --"Some people worry that artificial intelligence will make us feel inferior, but then, anybody in his right mind should have an inferiority complex every time he looks at a flower."
-- Alan Kay Saludos /\/\ /\ >< `/
diffstat for pystiebeleltron-0.2.0 pystiebeleltron-0.2.0 changelog | 13 patches/0001-Adapt-library-to-pymodbus-3.10.0-8.patch | 431 ++++++++++ patches/0002-Fix-constructor-of-StiebelEltronModbusError.patch | 24 patches/0003-Rewrite-mock-Modbus-server-for-pymodbus-3.13.0-API.patch | 98 ++ patches/series | 3 5 files changed, 569 insertions(+) diff -Nru pystiebeleltron-0.2.0/debian/changelog pystiebeleltron-0.2.0/debian/changelog --- pystiebeleltron-0.2.0/debian/changelog 2025-07-22 10:36:00.000000000 +0200 +++ pystiebeleltron-0.2.0/debian/changelog 2026-05-27 02:00:00.000000000 +0200 @@ -1,3 +1,16 @@ +pystiebeleltron (0.2.0-1.1) unstable; urgency=medium + + * Non-maintainer upload. + * Add upstream patch to adapt to pymodbus 3.10+ API. + Fixes FTBFS/runtime errors with python3-pymodbus >= 3.10.0. + * Add upstream patch to fix a typo in the StiebelEltronModbusError constructor + (__init vs __init__). + * Add Debian patch to rewrite mock Modbus server for pymodbus 3.13.0 API. + Fixes FTBFS caused by pymodbus 3.13.0 removing ModbusSequentialDataBlock(0, + ...) support and the ModbusDeviceContext getValues/setValues methods. + + -- Maximiliano Curia <[email protected]> Wed, 27 May 2026 00:00:00 +0000 + pystiebeleltron (0.2.0-1) unstable; urgency=medium * New upstream release. diff -Nru pystiebeleltron-0.2.0/debian/patches/0001-Adapt-library-to-pymodbus-3.10.0-8.patch pystiebeleltron-0.2.0/debian/patches/0001-Adapt-library-to-pymodbus-3.10.0-8.patch --- pystiebeleltron-0.2.0/debian/patches/0001-Adapt-library-to-pymodbus-3.10.0-8.patch 1970-01-01 01:00:00.000000000 +0100 +++ pystiebeleltron-0.2.0/debian/patches/0001-Adapt-library-to-pymodbus-3.10.0-8.patch 2026-05-27 02:00:00.000000000 +0200 @@ -0,0 +1,431 @@ +From: Maximiliano Curia <[email protected]> +Date: Wed, 27 May 2026 10:20:40 +0200 +Subject: Adapt library to pymodbus 3.10.0 (#8) + +Author: David Claybourne <[email protected]> +Origin: upstream, https://github.com/pail23/pystiebeleltron/commit/9fe7703f4e7bb9ed6c7bde5a7d8dc80b2c3e4f1 +Forwarded: not-needed +--- + example.py | 5 +++-- + pyproject.toml | 2 +- + pystiebeleltron/__init__.py | 24 ++++++++++++------------ + pystiebeleltron/lwz.py | 4 ++-- + pystiebeleltron/pystiebeleltron.py | 16 ++++++++-------- + pystiebeleltron/wpm.py | 4 ++-- + scripts/templates/lwztemplate.j2 | 4 ++-- + scripts/templates/wpmtemplate.j2 | 4 ++-- + test/mock_modbus_server.py | 34 +++++++++++++++++----------------- + test/test_pystiebeleltron.py | 4 ++-- + test/test_stiebel_eltron.py | 2 +- + uv.lock | 8 ++++---- + 12 files changed, 56 insertions(+), 55 deletions(-) + +diff --git a/example.py b/example.py +index a034dc2..e41e8e1 100755 +--- a/example.py ++++ b/example.py +@@ -5,7 +5,8 @@ from pymodbus.client import ModbusTcpClient as ModbusClient + + host_ip = "192.168.1.20" + host_port = 502 +-slave = 1 ++device_id = 1 ++ + + def test_function(mod, fun): + """Executes the given function on the Stiebel Heatpump and prints the result.""" +@@ -45,7 +46,7 @@ def main(): + timeout=2) + client.connect() + +- unit = pyse.StiebelEltronAPI(client, slave) ++ unit = pyse.StiebelEltronAPI(client, device_id) + unit.update() + + execute_tests(unit) +diff --git a/pyproject.toml b/pyproject.toml +index 2885619..1ae05e0 100644 +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -16,7 +16,7 @@ classifiers = [ + ] + requires-python = ">=3.10,<3.14" + dependencies = [ +- "pymodbus>=3.8.3", ++ "pymodbus (>=3.10.0,<4)", + ] + + [build-system] +diff --git a/pystiebeleltron/__init__.py b/pystiebeleltron/__init__.py +index 1b848cd..fc64c3b 100644 +--- a/pystiebeleltron/__init__.py ++++ b/pystiebeleltron/__init__.py +@@ -139,7 +139,7 @@ async def get_controller_model(host, port) -> ControllerModel: + inverter_data = await client.read_input_registers( + address=5001, + count=1, +- slave=1, ++ device_id=1, + ) + if not inverter_data.isError(): + value = client.convert_from_registers(inverter_data.registers, client.DATATYPE.UINT16) +@@ -159,10 +159,10 @@ class StiebelEltronAPI: + register_blocks: list[ModbusRegisterBlock], + host: str, + port: int = 502, +- slave: int = 1, ++ device_id: int = 1, + ) -> None: + """Initialize Stiebel Eltron communication.""" +- self._slave = slave ++ self._device_id = device_id + self._lock = asyncio.Lock() + self._host = host + self._client: AsyncModbusTcpClient = AsyncModbusTcpClient(host=host, port=port) +@@ -220,21 +220,21 @@ class StiebelEltronAPI: + descriptor = self.get_register_descriptor(register) + if descriptor is not None: + async with self._lock: +- await self._client.write_register(descriptor.address - 1, value=self.convert_value_to_modbus(value, descriptor), slave=1) ++ await self._client.write_register(descriptor.address - 1, value=self.convert_value_to_modbus(value, descriptor), device_id=1) + else: + raise ValueError("invalid register") + +- async def read_input_registers(self, slave, address, count): ++ async def read_input_registers(self, device_id, address, count): + """Read input registers.""" +- _LOGGER.debug(f"Reading {count} input registers from {address} with slave {slave}") ++ _LOGGER.debug(f"Reading {count} input registers from {address} with device_id {device_id}") + async with self._lock: +- return await self._client.read_input_registers(address, count=count, slave=slave) ++ return await self._client.read_input_registers(address, count=count, device_id=device_id) + +- async def read_holding_registers(self, slave, address, count): ++ async def read_holding_registers(self, device_id, address, count): + """Read holding registers.""" +- _LOGGER.debug(f"Reading {count} holding registers from {address} with slave {slave}") ++ _LOGGER.debug(f"Reading {count} holding registers from {address} with device_id {device_id}") + async with self._lock: +- return await self._client.read_holding_registers(address, count=count, slave=slave) ++ return await self._client.read_holding_registers(address, count=count, device_id=device_id) + + def convert_value_from_modbus(self, register, register_description: ModbusRegister) -> float | int | None: + """Convert a modbus value to a python value.""" +@@ -288,13 +288,13 @@ class StiebelEltronAPI: + heat_pump_data = None + if registerblock.register_type == RegisterType.INPUT_REGISTER: + heat_pump_data = await self.read_input_registers( +- slave=self._slave, ++ device_id=self._device_id, + address=registerblock.base_address, + count=registerblock.count, + ) + elif registerblock.register_type == RegisterType.HOLDING_REGISTER: + heat_pump_data = await self.read_holding_registers( +- slave=self._slave, ++ device_id=self._device_id, + address=registerblock.base_address, + count=registerblock.count, + ) +diff --git a/pystiebeleltron/lwz.py b/pystiebeleltron/lwz.py +index 3bd8121..ad490ee 100644 +--- a/pystiebeleltron/lwz.py ++++ b/pystiebeleltron/lwz.py +@@ -349,7 +349,7 @@ class OperatingMode(Enum): + + + class LwzStiebelEltronAPI(StiebelEltronAPI): +- def __init__(self, host: str, port: int = 502, slave: int = 1) -> None: ++ def __init__(self, host: str, port: int = 502, device_id: int = 1) -> None: + super().__init__( + [ + ModbusRegisterBlock(base_address=0, count=34, name="System Values", registers=LWZ_SYSTEM_VALUES_REGISTERS, register_type=RegisterType.INPUT_REGISTER), +@@ -361,7 +361,7 @@ class LwzStiebelEltronAPI(StiebelEltronAPI): + ], + host, + port, +- slave, ++ device_id, + ) + + async def async_update(self): +diff --git a/pystiebeleltron/pystiebeleltron.py b/pystiebeleltron/pystiebeleltron.py +index 9eb11dd..ba736c8 100644 +--- a/pystiebeleltron/pystiebeleltron.py ++++ b/pystiebeleltron/pystiebeleltron.py +@@ -178,13 +178,13 @@ B3_BUS_STATUS = { + class StiebelEltronAPI(): + """Stiebel Eltron API.""" + +- def __init__(self, conn: ModbusClientMixin, slave=1, update_on_read=False): ++ def __init__(self, conn: ModbusClientMixin, device_id=1, update_on_read=False): + """Initialize Stiebel Eltron communication.""" + self._conn = conn + self._block_1_input_regs = B1_REGMAP_INPUT + self._block_2_holding_regs = B2_REGMAP_HOLDING + self._block_3_input_regs = B3_REGMAP_INPUT +- self._slave = slave ++ self._device_id = device_id + self._update_on_read = update_on_read + + def update(self): +@@ -192,15 +192,15 @@ class StiebelEltronAPI(): + ret = True + try: + block_1_result_input = self._conn.read_input_registers( +- slave=self._slave, ++ device_id=self._device_id, + address=B1_START_ADDR, + count=len(self._block_1_input_regs)).registers + block_2_result_holding = self._conn.read_holding_registers( +- slave=self._slave, ++ device_id=self._device_id, + address=B2_START_ADDR, + count=len(self._block_2_holding_regs)).registers + block_3_result_input = self._conn.read_input_registers( +- slave=self._slave, ++ device_id=self._device_id, + address=B3_START_ADDR, + count=len(self._block_3_input_regs)).registers + except AttributeError: +@@ -258,7 +258,7 @@ class StiebelEltronAPI(): + # def set_raw_holding_register(self, name, value): + # """Write to register by name.""" + # self._conn.write_register( +-# slave=self._slave, ++# device_id=self._device_id, + # address=(self._holding_regs[name]['addr']), + # value=value) + +@@ -279,7 +279,7 @@ class StiebelEltronAPI(): + def set_target_temp(self, temp: float): + """Set the target room temperature (day)(HC1).""" + self._conn.write_register( +- slave=self._slave, ++ device_id=self._device_id, + address=( + self._block_2_holding_regs['ROOM_TEMP_HEAT_DAY_HC1']['addr']), + value=round(temp * 10.0)) +@@ -303,7 +303,7 @@ class StiebelEltronAPI(): + def set_operation(self, mode: str): + """Set the operation mode.""" + self._conn.write_register( +- slave=self._slave, ++ device_id=self._device_id, + address=(self._block_2_holding_regs['OPERATING_MODE']['addr']), + value=B2_OPERATING_MODE_WRITE.get(mode)) + +diff --git a/pystiebeleltron/wpm.py b/pystiebeleltron/wpm.py +index 6c7ffb1..832189e 100644 +--- a/pystiebeleltron/wpm.py ++++ b/pystiebeleltron/wpm.py +@@ -874,7 +874,7 @@ WPM_ENERGY_DATA_REGISTERS = { + + + class WpmStiebelEltronAPI(StiebelEltronAPI): +- def __init__(self, host: str, port: int = 502, slave: int = 1) -> None: ++ def __init__(self, host: str, port: int = 502, device_id: int = 1) -> None: + super().__init__( + [ + ModbusRegisterBlock(base_address=500, count=110, name="System Values", registers=WPM_SYSTEM_VALUES_REGISTERS, register_type=RegisterType.INPUT_REGISTER), +@@ -886,7 +886,7 @@ class WpmStiebelEltronAPI(StiebelEltronAPI): + ], + host, + port, +- slave, ++ device_id, + ) + + async def async_update(self): +diff --git a/scripts/templates/lwztemplate.j2 b/scripts/templates/lwztemplate.j2 +index 47b39ef..815b499 100644 +--- a/scripts/templates/lwztemplate.j2 ++++ b/scripts/templates/lwztemplate.j2 +@@ -42,14 +42,14 @@ class OperatingMode(Enum): + + class {{heatpump_type}}StiebelEltronAPI(StiebelEltronAPI): + +- def __init__(self, host: str, port: int = 502, slave: int = 1) -> None: ++ def __init__(self, host: str, port: int = 502, device_id: int = 1) -> None: + super().__init__([ + {% for registerblock in registers %} + ModbusRegisterBlock(base_address={{registerblock["base_address"]}}, count={{registerblock["count"]}}, name="{{registerblock["name"]}}", registers={{heatpump_type.upper()}}_{{python_name(registerblock["name"]).upper()}}_REGISTERS, register_type={{registerblock["register_type"]}}),{% endfor %} + ModbusRegisterBlock(base_address=4000, count=3, name="Energy Management Settings", registers=ENERGY_MANAGEMENT_SETTINGS_REGISTERS, register_type=RegisterType.HOLDING_REGISTER), + ModbusRegisterBlock(base_address=5000, count=2, name="Energy System Information", registers=ENERGY_SYSTEM_INFORMATION_REGISTERS, register_type=RegisterType.INPUT_REGISTER), + ], +- host, port, slave) ++ host, port, device_id) + + async def async_update(self): + """Request current values from heat pump.""" +diff --git a/scripts/templates/wpmtemplate.j2 b/scripts/templates/wpmtemplate.j2 +index 3dbe9cc..ebd947e 100644 +--- a/scripts/templates/wpmtemplate.j2 ++++ b/scripts/templates/wpmtemplate.j2 +@@ -21,14 +21,14 @@ class {{heatpump_type}}{{python_class_name(registerblock["name"])}}Registers(Isg + + class {{heatpump_type}}StiebelEltronAPI(StiebelEltronAPI): + +- def __init__(self, host: str, port: int = 502, slave: int = 1) -> None: ++ def __init__(self, host: str, port: int = 502, device_id: int = 1) -> None: + super().__init__([ + {% for registerblock in registers %} + ModbusRegisterBlock(base_address={{registerblock["base_address"]}}, count={{registerblock["count"]}}, name="{{registerblock["name"]}}", registers={{heatpump_type.upper()}}_{{python_name(registerblock["name"]).upper()}}_REGISTERS, register_type={{registerblock["register_type"]}}),{% endfor %} + ModbusRegisterBlock(base_address=4000, count=3, name="Energy Management Settings", registers=ENERGY_MANAGEMENT_SETTINGS_REGISTERS, register_type=RegisterType.HOLDING_REGISTER), + ModbusRegisterBlock(base_address=5000, count=2, name="Energy System Information", registers=ENERGY_SYSTEM_INFORMATION_REGISTERS, register_type=RegisterType.INPUT_REGISTER), + ], +- host, port, slave) ++ host, port, device_id) + + async def async_update(self): + """Request current values from heat pump.""" +diff --git a/test/mock_modbus_server.py b/test/mock_modbus_server.py +index 2b30d9e..0039dc5 100644 +--- a/test/mock_modbus_server.py ++++ b/test/mock_modbus_server.py +@@ -12,9 +12,9 @@ of nodes which can be helpful for testing monitoring software. + # --------------------------------------------------------------------------- # + from pymodbus.server import StartTcpServer, ServerStop + +-from pymodbus.device import ModbusDeviceIdentification ++from pymodbus.pdu.device import ModbusDeviceIdentification + from pymodbus.datastore import ModbusSequentialDataBlock +-from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext ++from pymodbus.datastore import ModbusDeviceContext, ModbusServerContext + + + class MockModbusServer(object): +@@ -51,8 +51,8 @@ class MockModbusServer(object): + # or simply do not pass them to have them initialized to 0x00 on the full + # address range:: + # +- # store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create()) +- # store = ModbusSlaveContext() ++ # store = ModbusDeviceContext(di = ModbusSequentialDataBlock.create()) ++ # store = ModbusDeviceContext() + # + # Finally, you are allowed to use the same DataBlock reference for every + # table or you you may use a seperate DataBlock for each table. +@@ -60,33 +60,33 @@ class MockModbusServer(object): + # the same data or not:: + # + # block = ModbusSequentialDataBlock(0x00, [0]*0xff) +- # store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) ++ # store = ModbusDeviceContext(di=block, co=block, hr=block, ir=block) + # + # The server then makes use of a server context that allows the server to +- # respond with different slave contexts for different unit ids. By default ++ # respond with different device_id contexts for different unit ids. By default + # it will return the same context for every unit id supplied (broadcast + # mode). + # However, this can be overloaded by setting the single flag to False + # and then supplying a dictionary of unit id to context mapping:: + # + # slaves = { +- # 0x01: ModbusSlaveContext(...), +- # 0x02: ModbusSlaveContext(...), +- # 0x03: ModbusSlaveContext(...), ++ # 0x01: ModbusDeviceContext(...), ++ # 0x02: ModbusDeviceContext(...), ++ # 0x03: ModbusDeviceContext(...), + # } +- # context = ModbusServerContext(slaves=slaves, single=False) ++ # context = ModbusServerContext(device_ids=device_ids, single=False) + # +- # The slave context can also be initialized in zero_mode which means that a ++ # The device_id context can also be initialized in zero_mode which means that a + # request to address(0-7) will map to the address (0-7). The default is + # False which is based on section 4.4 of the specification, so address(0-7) + # will map to (1-8):: + # +- # store = ModbusSlaveContext(..., zero_mode=True) ++ # store = ModbusDeviceContext(..., zero_mode=True) + # ----------------------------------------------------------------------- # +- store = ModbusSlaveContext( ++ store = ModbusDeviceContext( + hr=ModbusSequentialDataBlock(0, [0]*3000), + ir=ModbusSequentialDataBlock(0, [0]*3000)) +- self.context = ModbusServerContext(slaves=store, single=True) ++ self.context = ModbusServerContext(devices=store, single=True) + + # ----------------------------------------------------------------------- # + # initialize the server information +@@ -122,12 +122,12 @@ class MockModbusServer(object): + :param values: List of values + """ + assert register == 3 or register == 4 +- slave_id = 0x00 +- old_values = self.context[slave_id].getValues(register, ++ device_id = 0x00 ++ old_values = self.context[device_id].getValues(register, + address, count=1) + self.log.debug("Change value at address {} from {} to {}".format( + address, old_values, values)) +- self.context[slave_id].setValues(register, address, values) ++ self.context[device_id].setValues(register, address, values) + + def update_holding_register(self, address, value): + """ Update value of a holding register. +diff --git a/test/test_pystiebeleltron.py b/test/test_pystiebeleltron.py +index 9f4b3f6..93d7f57 100644 +--- a/test/test_pystiebeleltron.py ++++ b/test/test_pystiebeleltron.py +@@ -14,7 +14,7 @@ from pystiebeleltron import pystiebeleltron as pyse + # Modbus server connection details + host_ip = "127.0.0.1" #"192.168.1.20" + host_port = 5020 #502 +-slave = 1 ++device_id = 1 + + + class TestStiebelEltronApi: +@@ -49,7 +49,7 @@ class TestStiebelEltronApi: + def pyse_api(self, request, pymb_s): + # parameter pymb_s leads to call of fixture + mb_c = ModbusClient(host=host_ip, port=host_port, timeout=2) +- api = pyse.StiebelEltronAPI(mb_c, slave, update_on_read=True) ++ api = pyse.StiebelEltronAPI(mb_c, device_id, update_on_read=True) + + # Cleanup after last test (will run as well, if setup fails). + def fin(): +diff --git a/test/test_stiebel_eltron.py b/test/test_stiebel_eltron.py +index f31442d..a4c1014 100644 +--- a/test/test_stiebel_eltron.py ++++ b/test/test_stiebel_eltron.py +@@ -6,7 +6,7 @@ from pymodbus.pdu.register_message import ( + ) + + +-async def read_registers(client, address: int, *, count: int = 1, slave: int = 0, no_response_expected: bool = False) -> ReadInputRegistersResponse: ++async def read_registers(client, address: int, *, count: int = 1, device_id: int = 0, no_response_expected: bool = False) -> ReadInputRegistersResponse: + """Read a slice from the input register.""" + return ReadInputRegistersResponse(address=address, count=count, registers=list(range(count))) + +diff --git a/uv.lock b/uv.lock +index 561aea2..20eae47 100644 +--- a/uv.lock ++++ b/uv.lock +@@ -119,11 +119,11 @@ wheels = [ + + [[package]] + name = "pymodbus" +-version = "3.9.2" ++version = "3.11.0" + source = { registry = "https://pypi.org/simple" } +-sdist = { url = "https://files.pythonhosted.org/packages/9e/9f/434efbc3edd1445efca2c17d24877010746d65783ddbb937de753de6bec7/pymodbus-3.9.2.tar.gz", hash = "sha256:2d08ab7bf6d1abc55a87f4faa3a7b04f74d7310b8c9771c3d66ee5fccf2e25ac", size = 163040, upload-time = "2025-04-18T15:24:36.377Z" } ++sdist = { url = "https://files.pythonhosted.org/packages/b0/a7/ff43634e43fedc132e876f8b82b84c103b329f66297346f43e2e6c9c04a4/pymodbus-3.11.0.tar.gz", hash = "sha256:cbb12041d67a9bcd3ab1c6f39afc7c19f23bb770def2a660b8bb72779ba51ee4", size = 161346, upload-time = "2025-08-05T15:26:23.757Z" } + wheels = [ +- { url = "https://files.pythonhosted.org/packages/4c/7e/ae151f2750fb604247088774634fea321a178fb898cf8e961879825f9e41/pymodbus-3.9.2-py3-none-any.whl", hash = "sha256:292dcf859d6f232c30abc9753c1f0b7804771fd9c749641b32831de01b360b30", size = 165153, upload-time = "2025-04-18T15:24:34.428Z" }, ++ { url = "https://files.pythonhosted.org/packages/ec/cd/ab6f675ae0cac8ae25103eb8b2f97e907edd3c6fe153ef4ef1d030fc62ec/pymodbus-3.11.0-py3-none-any.whl", hash = "sha256:34ef7154b32edffff77b5babd9b9aab8b4c9a1404b8badfa86f12d9e14bce02e", size = 163531, upload-time = "2025-08-05T15:26:22.068Z" }, + ] + + [[package]] +@@ -143,7 +143,7 @@ dev = [ + ] + + [package.metadata] +-requires-dist = [{ name = "pymodbus", specifier = ">=3.8.3" }] ++requires-dist = [{ name = "pymodbus", specifier = ">=3.10.0,<4" }] + + [package.metadata.requires-dev] + dev = [ diff -Nru pystiebeleltron-0.2.0/debian/patches/0002-Fix-constructor-of-StiebelEltronModbusError.patch pystiebeleltron-0.2.0/debian/patches/0002-Fix-constructor-of-StiebelEltronModbusError.patch --- pystiebeleltron-0.2.0/debian/patches/0002-Fix-constructor-of-StiebelEltronModbusError.patch 1970-01-01 01:00:00.000000000 +0100 +++ pystiebeleltron-0.2.0/debian/patches/0002-Fix-constructor-of-StiebelEltronModbusError.patch 2026-05-27 02:00:00.000000000 +0200 @@ -0,0 +1,24 @@ +From: Maximiliano Curia <[email protected]> +Date: Wed, 27 May 2026 10:23:40 +0200 +Subject: Fix constructor of StiebelEltronModbusError + +Author: Manuel Stahl <[email protected]> +Origin: upstream, https://github.com/pail23/pystiebeleltron/commit/fdc754101ef28211e75cc162d9c2f0919be24418 +Forwarded: not-needed +--- + pystiebeleltron/__init__.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pystiebeleltron/__init__.py b/pystiebeleltron/__init__.py +index fc64c3b..124b36f 100644 +--- a/pystiebeleltron/__init__.py ++++ b/pystiebeleltron/__init__.py +@@ -111,7 +111,7 @@ def get_register_descriptor(descriptors: list[ModbusRegister], address: int) -> + class StiebelEltronModbusError(Exception): + """Exception during modbus communication.""" + +- def __init(self) -> None: ++ def __init__(self) -> None: + """Initialize the error.""" + super().__init__("Data error on the modbus") + diff -Nru pystiebeleltron-0.2.0/debian/patches/0003-Rewrite-mock-Modbus-server-for-pymodbus-3.13.0-API.patch pystiebeleltron-0.2.0/debian/patches/0003-Rewrite-mock-Modbus-server-for-pymodbus-3.13.0-API.patch --- pystiebeleltron-0.2.0/debian/patches/0003-Rewrite-mock-Modbus-server-for-pymodbus-3.13.0-API.patch 1970-01-01 01:00:00.000000000 +0100 +++ pystiebeleltron-0.2.0/debian/patches/0003-Rewrite-mock-Modbus-server-for-pymodbus-3.13.0-API.patch 2026-05-27 02:00:00.000000000 +0200 @@ -0,0 +1,98 @@ +From: Maximiliano Curia <[email protected]> +Date: Wed, 27 May 2026 00:00:00 +0000 +Subject: Rewrite mock Modbus server for pymodbus 3.13.0 API + +Origin: debian +Reason: pymodbus 3.13.0 rewrote the datastore API (ModbusSequentialDataBlock, + ModbusDeviceContext, ModbusServerContext) to use SimData/SimDevice internally, + breaking address=0 and removing getValues/setValues/context[id] access. + Rewrite the mock server to use the new SimData/SimDevice/ModbusTcpServer API + with asyncio.run_coroutine_threadsafe for thread-safe register updates. +--- + test/mock_modbus_server.py | 46 ++++++++++++++++++++++++++++++++++------------ + 1 file changed, 34 insertions(+), 12 deletions(-) + +diff --git a/test/mock_modbus_server.py b/test/mock_modbus_server.py +index 0039dc5..83adbb5 100644 +--- a/test/mock_modbus_server.py ++++ b/test/mock_modbus_server.py +@@ -10,11 +10,11 @@ of nodes which can be helpful for testing monitoring software. + # --------------------------------------------------------------------------- # + # import the various server implementations + # --------------------------------------------------------------------------- # +-from pymodbus.server import StartTcpServer, ServerStop ++import asyncio + + from pymodbus.pdu.device import ModbusDeviceIdentification +-from pymodbus.datastore import ModbusSequentialDataBlock +-from pymodbus.datastore import ModbusDeviceContext, ModbusServerContext ++from pymodbus.server import ModbusTcpServer ++from pymodbus.simulator import DataType, SimData, SimDevice + + + class MockModbusServer(object): +@@ -83,10 +83,23 @@ class MockModbusServer(object): + # + # store = ModbusDeviceContext(..., zero_mode=True) + # ----------------------------------------------------------------------- # +- store = ModbusDeviceContext( +- hr=ModbusSequentialDataBlock(0, [0]*3000), +- ir=ModbusSequentialDataBlock(0, [0]*3000)) +- self.context = ModbusServerContext(devices=store, single=True) ++ self._loop = asyncio.new_event_loop() ++ asyncio.set_event_loop(self._loop) ++ self._loop.run_until_complete(self._start_server()) ++ ++ async def _start_server(self): ++ device = SimDevice( ++ id=0, ++ simdata=( ++ [SimData(address=0, count=1, values=False, datatype=DataType.BITS)], ++ [SimData(address=0, count=1, values=False, datatype=DataType.BITS)], ++ [SimData(address=1000, count=27, datatype=DataType.REGISTERS)], ++ [ ++ SimData(address=0, count=33, datatype=DataType.REGISTERS), ++ SimData(address=2000, count=3, datatype=DataType.REGISTERS), ++ ], ++ ) ++ ) + + # ----------------------------------------------------------------------- # + # initialize the server information +@@ -106,10 +119,14 @@ class MockModbusServer(object): + # ----------------------------------------------------------------------- # + + # TCP Server +- StartTcpServer(self.context, identity=identity, address=("localhost", 5020)) ++ self._server = ModbusTcpServer( ++ device, identity=identity, address=("localhost", 5020)) ++ await self._server.serve_forever() + + def stop_async_server(self): +- ServerStop() ++ if hasattr(self, '_server') and hasattr(self, '_loop'): ++ asyncio.run_coroutine_threadsafe( ++ self._server.shutdown(), self._loop).result() + + def update_context(self, register, address, values): + """ Update values of the active context. It should be noted +@@ -123,11 +140,16 @@ class MockModbusServer(object): + """ + assert register == 3 or register == 4 + device_id = 0x00 +- old_values = self.context[device_id].getValues(register, +- address, count=1) ++ old_values = asyncio.run_coroutine_threadsafe( ++ self._server.async_getValues(device_id, register, address, count=1), ++ self._loop ++ ).result() + self.log.debug("Change value at address {} from {} to {}".format( + address, old_values, values)) +- self.context[device_id].setValues(register, address, values) ++ asyncio.run_coroutine_threadsafe( ++ self._server.async_setValues(device_id, register, address, values), ++ self._loop ++ ).result() + + def update_holding_register(self, address, value): + """ Update value of a holding register. diff -Nru pystiebeleltron-0.2.0/debian/patches/series pystiebeleltron-0.2.0/debian/patches/series --- pystiebeleltron-0.2.0/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ pystiebeleltron-0.2.0/debian/patches/series 2026-05-27 02:00:00.000000000 +0200 @@ -0,0 +1,3 @@ +0001-Adapt-library-to-pymodbus-3.10.0-8.patch +0002-Fix-constructor-of-StiebelEltronModbusError.patch +0003-Rewrite-mock-Modbus-server-for-pymodbus-3.13.0-API.patch
signature.asc
Description: PGP signature

