"""Integration test: pymodbus as an independent Modbus TCP master. Verifies the simulator against a third-party client implementation (rather than our own codec) — the strongest interop check for FAT use. Uses the pymodbus 3.15 async client API (device_id= keyword). """ from __future__ import annotations import asyncio import pytest pymodbus = pytest.importorskip("pymodbus") from pymodbus.client import AsyncModbusTcpClient # noqa: E402 async def _start(app, port=15021): app.server.host, app.server.port = "127.0.0.1", port await app.server.start() await asyncio.sleep(0.05) class TestPymodbusInterop: async def test_constants_via_pymodbus(self, app): await _start(app) client = AsyncModbusTcpClient("127.0.0.1", port=15021) assert await client.connect() try: rr = await client.read_holding_registers(0x2000, count=9, device_id=1) assert not rr.isError() assert rr.registers == [0x0000, 0xFFFF, 0x1234, 0xAAAA, 0x5555, 0x7FFF, 0x8000, 0x3FFF, 0x4000] finally: client.close() await app.server.stop() async def test_write_read_process_image(self, app): await _start(app) client = AsyncModbusTcpClient("127.0.0.1", port=15021) assert await client.connect() try: # write holding register 0 (-> output %QW0) await client.write_register(0, 0x1234, device_id=1) # read back via the input-register mirror at +0x0200 rr = await client.read_input_registers(0x0200, count=1, device_id=1) assert rr.registers == [0x1234] # coil write & read-back mirror at 0x0200 await client.write_coil(3, True, device_id=1) rr = await client.read_coils(0x0200, count=8, device_id=1) assert rr.bits[3] is True finally: client.close() await app.server.stop() async def test_illegal_address_exception(self, app): await _start(app) client = AsyncModbusTcpClient("127.0.0.1", port=15021) assert await client.connect() try: rr = await client.read_holding_registers(0x0100, count=1, device_id=1) assert rr.isError() assert rr.exception_code == 0x02 finally: client.close() await app.server.stop() async def test_read_write_multiple_registers(self, app): await _start(app) client = AsyncModbusTcpClient("127.0.0.1", port=15021) assert await client.connect() try: # FC23: read the constant 0x1234 at 0x2002 while writing %QW0 rr = await client.readwrite_registers( read_address=0x2002, read_count=1, write_address=0x0000, values=[0xBEEF], device_id=1, ) assert not rr.isError() assert rr.registers == [0x1234] # the write part landed in the output image -> mirror at 0x0200 rr = await client.read_input_registers(0x0200, count=1, device_id=1) assert rr.registers == [0xBEEF] finally: client.close() await app.server.stop()