aldas / modbus-tcp-client

PHP client for Modbus TCP and Modbus RTU over TCP (can be used for serial)
Apache License 2.0
191 stars 55 forks source link

connection refused #94

Closed anditsung closed 3 years ago

anditsung commented 3 years ago

hi, i dont really know if this an issue or not

i try to read the register from address 1 to 65 it was working fine but then i add to read register for 2001 till 2016 it will have connection refused error

i have try to read address 1 and 2001 only and have the same error but after i remove the 2001 everything working fine

i try to read only from 2001 to 2016 it was working fine

the problem only occur when i combine both address

===

seems the problem only occur if when the address is to big i try to read 100 and 200 working fine then read 100, 200 and 300 will return connection refused but if i read 200 and 300 working fine again

anditsung commented 3 years ago

https://github.com/aldas/modbus-tcp-client/blob/c39a0e51519c5ef76f6ff0f2fb8e36fb34de2935/src/Network/NonBlockingClient.php#L121-L156

seems the issue was here. if the connection was too fast it will return connection refused

i try to add sleep(1); after line 132 everything was working. but i dont think this is the perfect solution

anditsung commented 3 years ago
foreach ($requests as $indexOrKey => $request) {
                $uri = mb_strtolower($request->getUri());
                $packet = $request->getRequest();
                $connection = BinaryStreamConnection::getBuilder()
                    ->setFromOptions(array_merge($options, ['uri' => $uri]))
                    ->build();
                $connections[] = $connection->connect();

                $responsePackets[$indexOrKey] = $connection->sendAndReceive($packet);
            }

i try something like this. and i dont have any error at all can create a PR for this?

aldas commented 3 years ago

How many requests are you sending in parallel? I assume you are using examples/example_parallel_requests.php based code?

If you use sendAndReceive you are changing NonBlockingClient nature to be serial. Same goes with using long sleeps with NonBlockingClient. Sending requests serially could be right for your situation - It could be that your device does not handle parallel requests well.

If doing serially is OK you could just make little helper function to send requests like that:

function sendsRequests(array $requests): array
{
    $connection = BinaryStreamConnection::getBuilder()
        ->setPort('5022')
        ->setHost('127.0.0.1') // we assume that port and ip is not different over requests
        ->setConnectTimeoutSec(1.5) // timeout when establishing connection to the server
        ->setWriteTimeoutSec(0.5) // timeout when writing/sending packet to the server
        ->setReadTimeoutSec(1.0) // timeout when waiting response from server
        ->build();

    try {
        $connection->connect();

        $results = [];
        foreach ($requests as $index => $request) {
            $binaryData = $connection->sendAndReceive($request->getRequest()); // send/receive request serially
            $response = $request->parse($binaryData);

            if ($response instanceof ErrorResponse) {
                throw new ModbusException('sendRequests resulted with modbus error. msg: ' . $response->getErrorMessage());
            }
            $result[$index] = $response;
        }
        $result = new ResultContainer($results, []);
        return $result->getData(); // extract data to assoc array
    } finally {
        $connection->close();
    }
}

$requests = ReadRegistersBuilder::newReadHoldingRegisters('tcp://127.0.0.1:5022')
    ->bit(256, 15, 'pump2_feedbackalarm_do')
    // will be split into 2 requests as 1 request can return only range of 124 registers max
    ->int16(657, 'battery3_voltage_wo')
    ->build(); // returns array of 2 requests

print_r(sendsRequests($requests));
anditsung commented 3 years ago

wow... it was working thank you very much.. im using deltaww HMI some of the address have big different there is 1 till 65 then there is $M1 address that will read as 2001 till 2016 using your method will read any address without the problem except the result is not merge together

Screen Shot 2021-06-25 at 09 37 41
aldas commented 3 years ago

probably changing return to would help

return array_merge(...$result->getData()); 
anditsung commented 3 years ago

im doing something like this


$result = new ResultContainer($results, []);
            return collect($result->getData())->flatMap( function ($row) {
                return $row;
            });```