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

Attachment: signature.asc
Description: PGP signature

Reply via email to