Repository: pymodbus-dev/pymodbus

Issue:
pymodbus.server does not return any values
### Versions

- Python: 3.10.10
- OS: Fedora 36
- Pymodbus: 3.2.2

### Pymodbus Specific

- Server: tcp
- Client: tcp

### Description

- starting pymodbus.server: ```pymodbus.server run```
- starting pymodbus.client: ```pymodbus.console tcp --host localhost --port 5020```
- when trying to read some registers, the following error appears after a short timeout
```
> client.read_input_registers address 1 count 1 slave 1
{
    "message": "Broadcast message, ignoring errors!!!"
}
````
- the same worked in pymodus 2.5.3


Discussion:
Hmmm that is something I have not tested.


@dhoomakethu could you please take a look at this. I might have broken something among the many changes.
Did you try with another address, I think the datastore for the server was updated.
On the latest `master` branch I am hitting this issue. Will work on it.
```
❯ pymodbus.console tcp --host localhost --port 5020
Traceback (most recent call last):
  File "/Users/sanjay/.virtualenvs/pymodbus/bin/pymodbus.console", line 33, in <module>
    sys.exit(load_entry_point('pymodbus', 'console_scripts', 'pymodbus.console')())
  File "/Users/sanjay/.virtualenvs/pymodbus/lib/python3.8/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/Users/sanjay/.virtualenvs/pymodbus/lib/python3.8/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/Users/sanjay/.virtualenvs/pymodbus/lib/python3.8/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/sanjay/.virtualenvs/pymodbus/lib/python3.8/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/sanjay/.virtualenvs/pymodbus/lib/python3.8/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/Users/sanjay/.virtualenvs/pymodbus/lib/python3.8/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/main.py", line 310, in tcp
    cli(client)
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/main.py", line 177, in cli
    completer=CmdCompleter(client),
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/completer.py", line 39, in __init__
    self._commands = commands or get_commands(client)
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/helper.py", line 214, in get_commands
    requests = _get_requests(members)
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/helper.py", line 166, in _get_requests
    commands = {
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/helper.py", line 167, in <dictcomp>
    f"client.{c[0]}": Command(
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/helper.py", line 79, in __init__
    self.param_help = self._create_arg_help()
  File "/Users/sanjay/repo/pymodbus/pymodbus/repl/client/helper.py", line 105, in _create_arg_help
    param, param_help = param.split(":param")[1].strip().split(":")
ValueError: too many values to unpack (expected 2)
```
@chkr-private Please run your server with `pymodbus.server --verbose run` and paste the log here, I believe the the default unit id is `None` and which might be the reason why you are not receiving the values.
```
❯ pymodbus.server run --help

 Usage: pymodbus.server run [OPTIONS]

 Run Reactive Modbus server.
 Exposing REST endpoint for response manipulation.

╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --modbus-server       -s      TEXT     Modbus Server [default: tcp]                                                        │
│ --framer              -f      TEXT     Modbus framer to use [default: socket]                                              │
│ --modbus-port         -p      INTEGER  Modbus port [default: 5020]                                                         │
│ --unit-id             -u      INTEGER  Supported Modbus unit id's [default: None]                                          │
│ --modbus-config-path          PATH     Path to additional modbus server config [default: None]                             │
│ --random              -r      INTEGER  Randomize every `r` reads. 0=never, 1=always,2=every-second-read, and so on.        │
│                                        Applicable IR and DI.                                                               │
│                                        [default: 0]                                                                        │
│ --change-rate         -c      INTEGER  Rate in % registers to change. 0=none, 100=all, 12=12% of registers, and so on.     │
│                                        Applicable IR and DI.                                                               │
│                                        [default: 0]                                                                        │
│ --help                                 Show this message and exit.                                                         │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

```

Resolving patch:
diff --git a/pymodbus/repl/client/main.py b/pymodbus/repl/client/main.py
--- a/pymodbus/repl/client/main.py
+++ b/pymodbus/repl/client/main.py
@@ -277,7 +277,7 @@ def main(
         logging.basicConfig(format=use_format)
         _logger.setLevel(logging.DEBUG)
     ctx.obj = {
-        "broadcast": broadcast_support,
+        "broadcast_enable": broadcast_support,
         "retry_on_empty": retry_on_empty,
         "retry_on_invalid": retry_on_error,
         "retries": retries,
diff --git a/pymodbus/repl/client/mclient.py b/pymodbus/repl/client/mclient.py
--- a/pymodbus/repl/client/mclient.py
+++ b/pymodbus/repl/client/mclient.py
@@ -104,7 +104,7 @@ def read_coils(self, address, count=1, slave=Defaults.Slave, **kwargs):
         )
         if not resp.isError():
             return {"function_code": resp.function_code, "bits": resp.bits}
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=slave)
 
     def read_discrete_inputs(self, address, count=1, slave=Defaults.Slave, **kwargs):
         """Read `count` number of discrete inputs starting at offset `address`.
@@ -120,7 +120,7 @@ def read_discrete_inputs(self, address, count=1, slave=Defaults.Slave, **kwargs)
         )
         if not resp.isError():
             return {"function_code": resp.function_code, "bits": resp.bits}
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=slave)
 
     @handle_brodcast
     def write_coil(self, address, value, slave=Defaults.Slave, **kwargs):
@@ -196,7 +196,7 @@ def read_holding_registers(self, address, count=1, slave=Defaults.Slave, **kwarg
         )
         if not resp.isError():
             return {"function_code": resp.function_code, "registers": resp.registers}
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=slave)
 
     def read_input_registers(self, address, count=1, slave=Defaults.Slave, **kwargs):
         """Read `count` number of input registers starting at `address`.
@@ -212,7 +212,7 @@ def read_input_registers(self, address, count=1, slave=Defaults.Slave, **kwargs)
         )
         if not resp.isError():
             return {"function_code": resp.function_code, "registers": resp.registers}
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=slave)
 
     def readwrite_registers(
         self,
@@ -246,7 +246,7 @@ def readwrite_registers(
         )
         if not resp.isError():
             return {"function_code": resp.function_code, "registers": resp.registers}
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=slave)
 
     def mask_write_register(
         self,
@@ -275,7 +275,7 @@ def mask_write_register(
                 "and mask": resp.and_mask,
                 "or mask": resp.or_mask,
             }
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=slave)
 
     def read_device_information(self, read_code=None, object_id=0x00, **kwargs):
         """Read the identification and additional information of remote slave.
@@ -297,7 +297,7 @@ def read_device_information(self, read_code=None, object_id=0x00, **kwargs):
                 "more follows": resp.more_follows,
                 "space left": resp.space_left,
             }
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=request.slave_id)
 
     def report_slave_id(self, slave=Defaults.Slave, **kwargs):
         """Report information about remote slave ID.
@@ -315,7 +315,7 @@ def report_slave_id(self, slave=Defaults.Slave, **kwargs):
                 "status": resp.status,
                 "byte count": resp.byte_count,
             }
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=slave)
 
     def read_exception_status(self, slave=Defaults.Slave, **kwargs):
         """Read contents of eight Exception Status output in a remote device.
@@ -328,7 +328,7 @@ def read_exception_status(self, slave=Defaults.Slave, **kwargs):
         resp = self.execute(request)  # pylint: disable=no-member
         if not resp.isError():
             return {"function_code": resp.function_code, "status": resp.status}
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=request.slave_id)
 
     def get_com_event_counter(self, **kwargs):
         """Read status word and an event count.
@@ -346,7 +346,7 @@ def get_com_event_counter(self, **kwargs):
                 "status": resp.status,
                 "count": resp.count,
             }
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=request.slave_id)
 
     def get_com_event_log(self, **kwargs):
         """Read status word.
@@ -367,7 +367,7 @@ def get_com_event_log(self, **kwargs):
                 "event count": resp.event_count,
                 "events": resp.events,
             }
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=request.slave_id)
 
     def _execute_diagnostic_request(self, request):
         """Execute diagnostic request."""
@@ -378,7 +378,7 @@ def _execute_diagnostic_request(self, request):
                 "sub function code": resp.sub_function_code,
                 "message": resp.message,
             }
-        return ExtendedRequestSupport._process_exception(resp)
+        return ExtendedRequestSupport._process_exception(resp, slave=request.slave_id)
 
     def return_query_data(self, message=0, **kwargs):
         """Loop back data sent in response.


Test patch: