Coder Social home page Coder Social logo

giofranco / modbus-tcp-client Goto Github PK

View Code? Open in Web Editor NEW

This project forked from aldas/modbus-tcp-client

0.0 0.0 0.0 349 KB

PHP client for Modbus TCP and Modbus RTU over TCP (can be used for serial)

License: Apache License 2.0

PHP 99.89% Shell 0.11%

modbus-tcp-client's Introduction

Modbus TCP and RTU over TCP protocol client

Latest Version Packagist Software License codecov

Installation

Use Composer to install this library as dependency.

composer require aldas/modbus-tcp-client

Supported functions

Utility functions

Requirements

  • PHP 7.0+
  • Release 0.2.0 was last to support PHP 5.6

Intention

This library is influenced by phpmodbus library and meant to be provide decoupled Modbus protocol (request/response packets) and networking related features so you could build modbus client with our own choice of networking code (ext_sockets/streams/Reactphp/Amp asynchronous streams) or use library provided networking classes (php Streams)

Endianness

Applies to multibyte data that are stored in Word/Double/Quad word registers basically everything that is not (u)int16/byte/char.

So if we receive from network 0x12345678 (bytes: ABCD) and want to convert that to a 32 bit register there could be 4 different ways to interpret bytes and word order depending on modbus server architecture and client architecture. NB: TCP, and UDP, are transmitted in big-endian order so we choose this as base for examples

Library supports following byte and word orders:

  • Big endian (ABCD - word1 = 0x1234, word2 = 0x5678)
  • Big endian low word first (CDAB - word1 = 0x5678, word2 = 0x1234) (used by Wago-750)
  • Little endian (DCBA - word1 = 0x3412, word2 = 0x7856)
  • Little endian low word first (BADC - word1 = 0x7856, word2 = 0x3412)

See Endian.php for additional info and Types.php for supported data types.

Example of Modbus TCP (fc3 - read holding registers)

Some of the Modbus function examples are in examples/ folder

Advanced usage:

Request multiple packets with higher level API:

$address = 'tcp://127.0.0.1:5022';
$unitID = 0; // also known as 'slave ID'
$fc3 = ReadRegistersBuilder::newReadHoldingRegisters($address, $unitID)
    ->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')
    // will be another request as uri is different for subsequent int16 register
    ->useUri('tcp://127.0.0.1:5023')
    ->string(
        669,
        10,
        'username_plc2',
        function ($value, $address, $response) {
            return 'prefix_' . $value; // optional: transform value after extraction
        },
        function (\Exception $exception, Address $address, $response) {
            // optional: callback called then extraction failed with an error
            return $address->getType() === Address::TYPE_STRING ? '' : null; // does not make sense but gives you an idea
        }
    )
    ->build(); // returns array of 3 ReadHoldingRegistersRequest requests

// this will use PHP non-blocking stream io to recieve responses
$responses = (new NonBlockingClient(['readTimeoutSec' => 0.2]))->sendRequests($fc3);
print_r($responses);

Response structure

[
    [ 'pump2_feedbackalarm_do' => true, ],
    [ 'battery3_voltage_wo' => 12, ],
    [ 'username_plc2' => 'prefix_admin', ]
]

Low level - send packets:

$connection = BinaryStreamConnection::getBuilder()
    ->setHost('192.168.0.1')
    ->build();
    
$packet = new ReadHoldingRegistersRequest(256, 8); //create FC3 request packet

try {
    $binaryData = $connection->connect()->sendAndReceive($packet);

    //parse binary data to response object
    $response = ResponseFactory::parseResponseOrThrow($binaryData);
    
    //same as 'foreach ($response->getWords() as $word) {'
    foreach ($response as $word) { 
        print_r($word->getInt16());
    }
    // print registers as double words in big endian low word first order (as WAGO-750 does)
    foreach ($response->getDoubleWords() as $dword) {
        print_r($dword->getInt32(Endian::BIG_ENDIAN_LOW_WORD_FIRST));
    }
        
    // set internal index to match start address to simplify array access
    $responseWithStartAddress = $response->withStartAddress(256);
    print_r($responseWithStartAddress[256]->getBytes()); // use array access to get word
    print_r($responseWithStartAddress->getDoubleWordAt(257)->getFloat());
} catch (Exception $exception) {
    echo $exception->getMessage() . PHP_EOL;
} finally {
    $connection->close();
}

Example of Modbus RTU over TCP

Difference between Modbus RTU and Modbus TCP is that:

  1. RTU header contains only slave id. TCP/IP header contains of transaction id, protocol id, length, unitid
  2. RTU packed has 2 byte CRC appended

See http://www.simplymodbus.ca/TCP.htm for more detailsed explanation

This library was/is originally meant for Modbus TCP but it has support to convert packet to RTU and from RTU. See this examples/rtu.php for example.

$rtuBinaryPacket = RtuConverter::toRtu(new ReadHoldingRegistersRequest($startAddress, $quantity, $slaveId));
$binaryData = $connection->connect()->sendAndReceive($rtuBinaryPacket);
$responseAsTcpPacket = RtuConverter::fromRtu($binaryData);

Example of Modbus RTU over USB to Serial (RS485) adapter

See Linux example in 'examples/rtu_usb_to_serial.php'

Example of non-blocking socket IO with ReactPHP/Amp (i.e. modbus request are run in 'parallel')

Example Modbus server (accepting requests) with ReactPHP

Try communication with PLCs quickly using php built-in web server

Examples folder has index.php which can be used with php built-in web server to test out communication with our own PLCs.

git clone https://github.com/aldas/modbus-tcp-client.git
cd modbus-tcp-client
composer install
php -S localhost:8080 -t examples/

Now open http://localhost:8080 in browser. See additional query parameters from index.php.

Changelog

See CHANGELOG.md

Tests

  • all composer test
  • unit tests composer test-unit
  • integration tests composer test-integration

For Windows users:

  • all vendor/bin/phpunit
  • unit tests vendor/bin/phpunit --testsuite 'unit-tests'
  • integration tests vendor/bin/phpunit --testsuite 'integration-tests'

modbus-tcp-client's People

Contributors

aldas avatar samvdb avatar harli91 avatar weesee avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.