87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
"""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() |