Closed jonofe closed 1 year ago
Hi,
For me this seems to be question about difference between NonBlockingClient
and BinaryStreamConnection
. Let me try to explain
BinaryStreamConnection is mean to transfer single modbus packet. It opens single connection and reads data from it. This means that during $connection->sendAndReceive($packet)
you have single connection open. Note: $connection->close()/connect()
NonBlockingClient is meant to transer multiple packets at the same time. It opens connection for each packet and waits until all packet connections have received their responses. It handles $connection->close()/connect()
for you. NB: NonBlockingClient
uses internally BinaryStreamConnection
for its connection.
Both these use same code to receive data from the connection
At the moment I see some differences between these 2 in your code - they have different timeout options.
Try to provide NonBlockingClient
same options has BinaryStreamConnection
has.
$client = new NonBlockingClient([
'connectTimeoutSec' => 1.5,
'readTimeoutSec' => 0.5,
'writeTimeoutSec' => 0.5,
]);
Also worth noting: these embbeded devices have limitations how many open connections and lingering connections they can have. As NonBlockingClient
calls $connection->close()
inside sendRequests
and BinaryStreamConnection
needs explicit $connection->close()
call (that you do no have inside for loop) - you have different amount of closed sockets after couple for loop iterations. I do not know this could make the difference at the moment but I have experienced that closing/reusing connections is a big deal for these low-powered devices.
but I assume at the moment that problems is about these timeout. Your NonBlockingClient
block defaults to smaller timeouts.
Martti, thanks for your feedback. I took it into consideration for further debugging with the following results. I'm now able to reproduce the "faulty" behaviour by using the low level API. This is possible by placing a $connection->close() inside the while loop. This means, when closing the connection explicitely (and no other connection to the Modbus Master ist open, then I get this timeout behaviour (getting 12 times the same value followed by an timeout exception). When I look into the connection states of my TCP connections I find a lot of connection in the TIME_WAIT state, i.e. my client (low level API or high level API) has closed connection and is waiting whether delayed packets will still arrive. New connections seem to be delayed then by 6 seconds, so for 6 seconds the Modbus Master sends the old data and then the timeout happens and a new connection is allowed. What is not clear to me is, why another connection from another PC to the Modbus Master is preventing that behaviour to happen. In general it seems to me a kind of problem with the TCP connection management of my TCP Modbus Master.
Is there any way to use the high level API by reusing an existing connection?
I think I have not done good job with the readme. Higher lever API just refers to some components that do something extra. And you can mix these *builder components/classes with lower level network components/classes and vice versa.
See https://github.com/aldas/modbus-tcp-client/blob/master/examples/rtu_over_tcp_with_higherlevel_api.php
That example is using ReadRegistersBuilder
with BinaryStreamConnection
- so for your needs - create the connection , connect to it and reuse it in you while loop. Probably needs some catching to detect problems with the connection and then reconnect.
NB: you could use even ReactPHP networking. See this example: https://github.com/aldas/modbus-tcp-client/blob/master/examples/example_cli_poller.php
Hi guys, I have a problem, when using higher level API in comparison to low level API. I'm reading from a WAGO energy meter via modbus. The energy meter is connected via a Waveshare RS485 to RJ45 Ethernet Converter Module, Industrial Rail-Mount Module. When using low level API, I'm able to read every 200-500ms and I'm getting always updated values. When using the higher level API, I'm getting around 10 times the same value and then a "read total timeout expired".
What is really strange is, when I'm reading via the higher level API in a loop with the behaviour as mentioned above and then I'm starting a parallel connection to the modbus converter with for example QModbusMaster (Windows TCP Modbus Client), all of a sudden the higher level API is working correctly, means getting updated data every 200ms. When disconnecting the QModusMaster it's switching to the timeout behaviour. Same is true for modpoll. If I run modpoll in parallel, the higher level API is working correctly, when stopped, it changes back to the faulty behaviour. Again more strange is, that I only need a connection via QModbusMaster, I don't need to read data to make my higher level API script working.
Here is my code with higher level API ($option=1) and with low level API ($option=2). I'm calling the script with 2 parameters: 1st parameter: $interval in ms to read via Modbus in a loop 2nd parameter: $option: 1=higher level API / 2=low level API
How can a secondary Modbus connection (QModbusMaster or modpoll) influence the behaviour of the higher level API requests. Is there something missing in my higher level API code? I tried all the different timing settings, without any change.
Any help is very much appreciated!