Skip to content

Commit d5fbb48

Browse files
authored
Update datastore remote to handle write requests (#1166)
* Update datastore remote to handle write requests.
1 parent ed09435 commit d5fbb48

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

Diff for: examples/modbus_forwarder.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
#!/usr/bin/env python3
22
"""Pymodbus synchronous forwarder.
33
4-
This is a repeater or converter and an example of just how powerful datastore is.
4+
This is a repeater or converter and an example of just how powerful datastore is.
55
6-
It consist of a server (any comm) and a client (any comm) and basically all request
7-
received by the server is sent by client and all responses received by the
8-
client is sent back by the server.
6+
It consist of a server (any comm) and a client (any comm), functionality:
7+
8+
a) server receives a read/write request from external client:
9+
10+
- client sends a new read/write request to target server
11+
- client receives response and updates the datastore
12+
- server sends new response to external client
913
1014
Both server and client are tcp based, but it can be easily modified to any server/client
1115
(see client_sync.py and server_sync.py for other communication types)
@@ -69,5 +73,7 @@ async def run_forwarder(args):
6973
)
7074
],
7175
)
76+
cmd_args.port = 5021
77+
cmd_args.client_port = 5020
7278
run_args = setup_forwarder(cmd_args)
7379
asyncio.run(run_forwarder(run_args))

Diff for: pymodbus/datastore/remote.py

+25-5
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,18 @@ def validate(self, fc_as_hex, address, count=1):
4949
"""
5050
txt = f"validate[{fc_as_hex}] {address}:{count}"
5151
_logger.debug(txt)
52-
self.result = self.__get_callbacks[self.decode(fc_as_hex)](address, count)
52+
group_fx = self.decode(fc_as_hex)
53+
if fc_as_hex in self._write_fc:
54+
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
55+
else:
56+
func_fc = self.__get_callbacks[group_fx]
57+
self.result = func_fc(address, count)
5358
return not self.result.isError()
5459

5560
def getValues(self, fc_as_hex, address, count=1):
5661
"""Get values from real call in validate"""
62+
if fc_as_hex in self._write_fc:
63+
return [0]
5764
return self.__extract_result(self.decode(fc_as_hex), self.result)
5865

5966
def setValues(self, fc_as_hex, address, values):
@@ -89,19 +96,32 @@ def __build_mapping(self):
8996
),
9097
}
9198
self.__set_callbacks = {
92-
"d": lambda a, v: self._client.write_coils( # pylint: disable=unnecessary-lambda
99+
"d5": lambda a, v: self._client.write_coil( # pylint: disable=unnecessary-lambda
100+
a, v, **kwargs
101+
),
102+
"d15": lambda a, v: self._client.write_coils( # pylint: disable=unnecessary-lambda
103+
a, v, **kwargs
104+
),
105+
"c5": lambda a, v: self._client.write_coils( # pylint: disable=unnecessary-lambda
106+
a, v, **kwargs
107+
),
108+
"c15": lambda a, v: self._client.write_coils( # pylint: disable=unnecessary-lambda
109+
a, v, **kwargs
110+
),
111+
"h6": lambda a, v: self._client.write_register( # pylint: disable=unnecessary-lambda
93112
a, v, **kwargs
94113
),
95-
"c": lambda a, v: self._client.write_coils( # pylint: disable=unnecessary-lambda
114+
"h16": lambda a, v: self._client.write_registers( # pylint: disable=unnecessary-lambda
96115
a, v, **kwargs
97116
),
98-
"h": lambda a, v: self._client.write_registers( # pylint: disable=unnecessary-lambda
117+
"i6": lambda a, v: self._client.write_register( # pylint: disable=unnecessary-lambda
99118
a, v, **kwargs
100119
),
101-
"i": lambda a, v: self._client.write_registers( # pylint: disable=unnecessary-lambda
120+
"i16": lambda a, v: self._client.write_registers( # pylint: disable=unnecessary-lambda
102121
a, v, **kwargs
103122
),
104123
}
124+
self._write_fc = (0x05, 0x06, 0x15, 0x16, 0x17)
105125

106126
def __extract_result(self, fc_as_hex, result):
107127
"""Extract the values out of a response.

Diff for: test/test_examples.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
from examples.client_calls import run_async_calls, run_sync_calls
1313
from examples.client_payload import run_binary_payload_client
1414
from examples.client_sync import run_sync_client, setup_sync_client
15-
from examples.modbus_forwarder import run_forwarder, setup_forwarder
15+
from examples.modbus_forwarder import setup_forwarder
16+
17+
# from examples.modbus_forwarder import run_forwarder, setup_forwarder
1618
from examples.server_async import run_async_server, setup_server
1719
from examples.server_payload import run_payload_server
1820
from examples.server_sync import run_sync_server
@@ -171,16 +173,16 @@ async def test_exp_forwarder( # pylint: disable=unused-argument
171173
"""Test modbus forwarder."""
172174
if pytest.IS_WINDOWS:
173175
return
174-
return
175176

176-
pymodbus_apply_logging_config() # pylint: disable=unreachable
177+
pymodbus_apply_logging_config()
177178
cmd_args = Commandline
178179
cmd_args.comm = test_comm
179180
cmd_args.framer = test_framer
180181
cmd_args.port = test_port + test_port_offset + 1
181182
cmd_args.client_port = test_port + test_port_offset
182183
run_args = setup_forwarder(cmd_args)
183-
task = asyncio.create_task(run_forwarder(run_args))
184+
# task = asyncio.create_task(run_forwarder(run_args))
185+
task = asyncio.create_task(run_async_server(run_args))
184186
await asyncio.sleep(0.1)
185187

186188
real_client = AsyncModbusTcpClient(host="127.0.0.1", port=cmd_args.port)
@@ -191,6 +193,16 @@ async def test_exp_forwarder( # pylint: disable=unused-argument
191193
assert check_client.connected
192194
await asyncio.sleep(0.1)
193195

196+
# rr = _check_call(client.read_holding_registers(1, 1, slave=SLAVE))
197+
# rr = _check_call(client.read_coils(1, 1, slave=SLAVE))
198+
# rr = _check_call(client.read_discrete_inputs(0, 8, slave=SLAVE))
199+
# rr = _check_call(client.read_input_registers(1, 8, slave=SLAVE))
200+
# --
201+
# rr = _check_call(client.write_register(1, 10, slave=SLAVE))
202+
# rr = _check_call(client.write_coil(0, True, slave=SLAVE))
203+
# rr =_check_call(client.write_registers(1, [10] * 8, slave=SLAVE))
204+
# rr = _check_call(client.write_coils(1, [True] * 21, slave=SLAVE))
205+
194206
# Verify read values are identical
195207
# rr_real = await real_client.read_holding_registers(1,1,slave=1)
196208
# assert rr_real.registers, f"---> {rr_real}"

0 commit comments

Comments
 (0)