pyModbusTCP PC to PC connection

1.8k views Asked by At

I'm trying to connect two pcs together using pyModbusTCP. When I run both the client and server locally using local host it works just fine.

When I try and run them on separate PC's the client takes a while to "connect" and then just reads the registers as "None". I have set a static IP address for the server as 192.254.100.101 and can ping it using terminal on the other PC. I also have a static IP address on the client side of 192.254.100.102.

Client Code:

    from pyModbusTCP.client import ModbusClient
    import time
    
    client = ModbusClient(host="192.254.100.101", port=502, debug = True)
    
    print("Opening client")
    client.open()
    print("Client open")
    try:
    
        while True:
    
            value = client.read_holding_registers(0)
            print(f"Register 0: {value}")
    
            time.sleep(1)
    
    
    except:
    
        print("Shutdown")

Server code:

    from pyModbusTCP.server import ModbusServer, DataBank
    import time
    
    server =  ModbusServer(host= "192.254.100.101", port = 502, no_block=True)
    server.start()
    try: 
        print("Starting server...")
        server.start()
        print("Server is online")
        val = [0]
        while True:
            val0 = input("Val: ")
            val = [int(val0)]
            print(val)
            DataBank.set_words(0, val)
            time.sleep(0.5)
    
    except:
        print("Shutdown server")
        server.stop()

1

There are 1 answers

0
aniran mohammadpour On

.i.e:

you have a Raspberry pi with the static IP address of "192.254.100.101" and some devices are connected to it, then when you send a request to it you will declare the slave id number too, here you requested a data register.

now in the server app, you will return the answer using the sender packet IP address.

Use Wireshark and your local network for understanding.

Codes in java language Using Modbus4J:

public class MasterTest {
public static void main(String[] args) throws Exception {

//        String host = "localhost";
          String host = "192.168.1.105";
//        String host = "YOUR-DEVICE-IP-THAT-IS-CONNECTED-TO-NETWORK";

        IpParameters ipParameters = new IpParameters();

        ipParameters.setHost(host);
        ipParameters.setPort(502);
        ipParameters.setEncapsulated(false);

        ModbusFactory modbusFactory = new ModbusFactory();



       //TcpMaster extends ModbusMaster + Creates an object with ipParameters in it
        ModbusMaster master = modbusFactory.createTcpMaster(ipParameters, true);
//        ModbusMaster master = modbusFactory.createTcpMaster(ipParameters, false);
        master.setTimeout(8000);
        master.setRetries(0);
        // openConnection method will be called - if KeepAlive be true - openConnection is in TcpMaster
        // openConnection method will close other connections
        // Socket.connect(ipParameters.getHost(), ipParameters.getPort(),getTimeout()) is in openConnection method
        master.init();

        try {
//          master.send(new WriteCoilRequest(3, 120, true));
//          master.send(new WriteCoilRequest(3, 256, false));
            master.send(new ReadCoilsRequest(1, 17, 1));
            master.send(new ReadCoilsRequest(3, 256, 1));



 master.send(new WriteRegisterRequest(2, 15, 5));
    ReadHoldingRegistersResponse rresponse = (ReadHoldingRegistersResponse) master
            .send(new ReadHoldingRegistersRequest(1, 15, 1));
    System.out.println(rresponse);

//            System.out.println(master.testSlaveNode(1));
    } catch (Exception e) {
        e.printStackTrace();
    }

    master.destroy();

}
}

Slave codes in Java using Modbus4J:

public class SlaveTest {

static Random random = new Random();
static float ir1Value = -100;

//TEST VALUES
private static Integer twoByteIntUnsignedSwapped = 29187; //Register 16
private static Integer twoByteIntSignedSwapped = -257; //Register 17
private static Long fourByteIntUnsignedSwappedSwapped = 16777216L; //Register 18
private static Long fourByteIntSignedSwappedSwapped = (long) -16777217; //Register 20
private static Long register22 = 2369850368L; ////Register 22


public static void main(String[] args) {
    ModbusFactory modbusFactory = new ModbusFactory();
    ModbusSlaveSet slave = modbusFactory.createTcpSlave(false);
    slave.addProcessImage(getModscanProcessImage(1));

    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                slave.start();
            } catch (ModbusInitException e) {
                e.printStackTrace();
            }
        }
    }).start();

    while (true) {
        synchronized (slave) {
            try {
                slave.wait(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for (ProcessImage processImage : slave.getProcessImages()) {
            try {
                updateProcessImage((BasicProcessImage) processImage);
            } catch (IllegalDataAddressException e) {
                e.printStackTrace();
            }
        }
    }

}

static void updateProcessImage(BasicProcessImage processImage) throws IllegalDataAddressException {

    int hr16Value = processImage.getNumeric(RegisterRange.HOLDING_REGISTER, 16, DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED).intValue();
    if (hr16Value != twoByteIntUnsignedSwapped) {
        throw new RuntimeException("Test failed on TWO_BYTE_INT_UNSIGNED_SWAPPED. Expected " + twoByteIntUnsignedSwapped + " but was: " + hr16Value);
    }

    short hr17Value = processImage.getNumeric(RegisterRange.HOLDING_REGISTER, 17, DataType.TWO_BYTE_INT_SIGNED_SWAPPED).shortValue();
    if (hr17Value != twoByteIntSignedSwapped) {
        throw new RuntimeException("Test failed on TWO_BYTE_INT_SIGNED_SWAPPED. Expected " + twoByteIntSignedSwapped + " but was: " + hr17Value);
    }

    long hr18Value = processImage.getNumeric(RegisterRange.HOLDING_REGISTER, 18, DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED).longValue();
    if (hr18Value != fourByteIntUnsignedSwappedSwapped) {
        throw new RuntimeException("Test failed on FOUR_BYTE_INT_UNSIGNED_SWAPPED_INVERTED. Expected " + fourByteIntUnsignedSwappedSwapped + "  but was: " + hr18Value);
    }

    int hr20Value = processImage.getNumeric(RegisterRange.HOLDING_REGISTER, 20, DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED).intValue();
    if (hr20Value != fourByteIntSignedSwappedSwapped) {
        throw new RuntimeException("Test failed on FOUR_BYTE_INT_SIGNED_SWAPPED_INVERTED. Expected  " + fourByteIntSignedSwappedSwapped + "  but was: " + hr20Value);
    }

    long hr22Value = processImage.getNumeric(RegisterRange.HOLDING_REGISTER, 22, DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED).longValue();
    if (hr22Value != register22) {
        throw new RuntimeException("Test failed on FOUR_BYTE_INT_UNSIGNED_SWAPPED_INVERTED. Expected " + register22 + " but was: " + hr22Value);
    }

}

static class BasicProcessImageListener implements ProcessImageListener {
    @Override
    public void coilWrite(int offset, boolean oldValue, boolean newValue) {
        System.out.println("Coil at " + offset + " was set from " + oldValue + " to " + newValue);
    }

    @Override
    public void holdingRegisterWrite(int offset, short oldValue, short newValue) {
        // Add a small delay to the processing.
        //            try {
        //                Thread.sleep(500);
        //            }
        //            catch (InterruptedException e) {
        //                // no op
        //            }
        System.out.println("HR at " + offset + " was set from " + oldValue + " to " + newValue);
    }
}

static BasicProcessImage getModscanProcessImage(int slaveId) {
    BasicProcessImage processImage = new BasicProcessImage(slaveId);
    //processImage.setAllowInvalidAddress(true);
    processImage.setInvalidAddressValue(Short.MIN_VALUE);


    //Register 16 Holds 1 and the data is transmitted as 0b00000001 00000000 which is 256
    //processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 16, DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED, new Integer(256));
    processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 16, DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED, 29187);
    //Registery 16 Holds -2 and the data is transmitted as 0b1111110 11111111 which is -257
    processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 17, DataType.TWO_BYTE_INT_SIGNED_SWAPPED, -257);

    //Register 18 Holds 1 and the data is transmitted as 0b00000001 00000000 00000000 00000000 which is 16777216
    processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 18, DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED, 16777216L);

    //Register 20 Holds -2 and the data is transmitted as 0b1111110 11111111 1111111 11111111 which is -16777217
    processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 20, DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED, (long) -16777217);

    //Register 22 Holds 803213 and the data is transmitted as 0b10001101 01000001 00001100 00000000 which is 2369850368
    processImage.setNumeric(RegisterRange.HOLDING_REGISTER, 22, DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED, 2369850368L);


    processImage.setExceptionStatus((byte) 151);

    // Add an image listener.
    processImage.addListener(new BasicProcessImageListener());

    return processImage;
}
}

Slave codes for Wemos D1 (device) C language and Arduino IDE:

#include <ESP8266WiFi.h>


const char* ssid = "YOUR-WIFI-NAME";
const char* password = "YOUR-PASS";
int ModbusTCP_port = 502;
 
//////// Required for Modbus TCP / IP /// Requerido para Modbus TCP/IP /////////
#define maxInputRegister 20
#define maxHoldingRegister 20
 
#define MB_FC_NONE 0
#define MB_FC_READ_REGISTERS 3 //implemented
#define MB_FC_WRITE_REGISTER 6 //implemented
#define MB_FC_WRITE_MULTIPLE_REGISTERS 16 //implemented
//
// MODBUS Error Codes
//
#define MB_EC_NONE 0
#define MB_EC_ILLEGAL_FUNCTION 1
#define MB_EC_ILLEGAL_DATA_ADDRESS 2
#define MB_EC_ILLEGAL_DATA_VALUE 3
#define MB_EC_SLAVE_DEVICE_FAILURE 4
//
// MODBUS MBAP offsets
//
#define MB_TCP_TID 0
#define MB_TCP_PID 2
#define MB_TCP_LEN 4
#define MB_TCP_UID 6
#define MB_TCP_FUNC 7
#define MB_TCP_REGISTER_START 8
#define MB_TCP_REGISTER_NUMBER 10
 
byte ByteArray[260];
unsigned int MBHoldingRegister[maxHoldingRegister];
 
//////////////////////////////////////////////////////////////////////////



WiFiServer MBServer(ModbusTCP_port);



void setup() {
  pinMode(14, OUTPUT);
 
  Serial.begin(9600);
  delay(100);
  WiFi.begin(ssid, password);
  delay(100);
  Serial.println(".");
 
  while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }

  MBServer.begin();
  Serial.println("Connected ");
  Serial.print("ESP8266 Slave Modbus TCP/IP ");
  Serial.print(WiFi.localIP()); Serial.print(":"); Serial.println(String(ModbusTCP_port));
  Serial.println("Modbus TCP/IP Online");
}
 
 
void loop() {
  // Check if a client has connected // Modbus TCP/IP
  WiFiClient client = MBServer.available();
  if (!client) { return; }

  boolean flagClientConnected = 0;
  byte byteFN = MB_FC_NONE;
  int Start;
  int WordDataLength;
  int ByteDataLength;
  int MessageLength;
 
  // Modbus TCP/IP
  while (client.connected()) {
    if(client.available()) {
      flagClientConnected = 1;
      int i = 0;
      while(client.available()) {
    ByteArray[i] = client.read();
    i++;
  }
  client.flush();

  ///// code here --- codigo aqui

  ///////// Holding Register [0] A [9] = 10 Holding Registers Escritura
  ///////// Holding Register [0] A [9] = 10 Holding Registers Writing

  MBHoldingRegister[0] = random(0,12);
  MBHoldingRegister[1] = random(0,12);
  MBHoldingRegister[2] = random(0,12);
  MBHoldingRegister[3] = random(0,12);
  MBHoldingRegister[4] = random(0,12);
  MBHoldingRegister[5] = random(0,12);
  MBHoldingRegister[6] = random(0,12);
  MBHoldingRegister[7] = random(0,12);
  MBHoldingRegister[8] = random(0,12);
  MBHoldingRegister[9] = random(0,12);

  ///////// Holding Register [10] A [19] = 10 Holding Registers Lectura
  ///// Holding Register [10] A [19] = 10 Holding Registers Reading

  int Temporal[10];

  Temporal[0] = MBHoldingRegister[10];
  Temporal[1] = MBHoldingRegister[11];
  Temporal[2] = MBHoldingRegister[12];
  Temporal[3] = MBHoldingRegister[13];
  Temporal[4] = MBHoldingRegister[14];
  Temporal[5] = MBHoldingRegister[15];
  Temporal[6] = MBHoldingRegister[16];
  Temporal[7] = MBHoldingRegister[17];
  Temporal[8] = MBHoldingRegister[18];
  Temporal[9] = MBHoldingRegister[19];

  /// Enable Output 14
  digitalWrite(14, MBHoldingRegister[14] );

  //// debug
  for (int i = 0; i < 10; i++) {
   Serial.print("[");
    Serial.print(i);
    Serial.print("] ");
    Serial.print(Temporal[i]);
  }
  Serial.println("");

  //// end code - fin 


  //// routine Modbus TCP
  byteFN = ByteArray[MB_TCP_FUNC];
  Start = word(ByteArray[MB_TCP_REGISTER_START],ByteArray[MB_TCP_REGISTER_START+1]);
  WordDataLength = word(ByteArray[MB_TCP_REGISTER_NUMBER],ByteArray[MB_TCP_REGISTER_NUMBER+1]);
}

// Handle request
switch(byteFN) {

  case MB_FC_NONE:
    break;

  case MB_FC_READ_REGISTERS: // 03 Read Holding Registers
    ByteDataLength = WordDataLength * 2;
    ByteArray[5] = ByteDataLength + 3; //Number of bytes after this one.
    ByteArray[8] = ByteDataLength; //Number of bytes after this one (or number of bytes of data).
    for(int i = 0; i < WordDataLength; i++) {
      ByteArray[ 9 + i * 2] = highByte(MBHoldingRegister[Start + i]);
      ByteArray[10 + i * 2] = lowByte(MBHoldingRegister[Start + i]);
    }
    MessageLength = ByteDataLength + 9;
    client.write((const uint8_t *)ByteArray,MessageLength);
    byteFN = MB_FC_NONE;
    break;

  case MB_FC_WRITE_REGISTER: // 06 Write Holding Register
    MBHoldingRegister[Start] = word(ByteArray[MB_TCP_REGISTER_NUMBER],ByteArray[MB_TCP_REGISTER_NUMBER+1]);
    ByteArray[5] = 6; //Number of bytes after this one.
    MessageLength = 12;
    client.write((const uint8_t *)ByteArray,MessageLength);
    byteFN = MB_FC_NONE;
    break;

  case MB_FC_WRITE_MULTIPLE_REGISTERS: //16 Write Holding Registers
    ByteDataLength = WordDataLength * 2;
    ByteArray[5] = ByteDataLength + 3; //Number of bytes after this one.
    for(int i = 0; i < WordDataLength; i++) {
      MBHoldingRegister[Start + i] = word(ByteArray[ 13 + i * 2],ByteArray[14 + i * 2]);
    }
    MessageLength = 12;
    client.write((const uint8_t *)ByteArray,MessageLength); 
    byteFN = MB_FC_NONE;
    break;
}
  }
}

Client Code in python with pyModbusTCP:

#!/usr/bin/env python



from pyModbusTCP.client import ModbusClient
 
client = ModbusClient(host="192.168.1.105", port=502, auto_open=True, auto_close=True, timeout=10)
data2 = client.write_single_register(14, 1) # FUNCTIE 06 - (Write register) (register=14, data=1)
data = client.read_holding_registers(14, 1) # FUNCTIE 03 - Read register (enkele register) (register=14, length=1)
print ("Data register: ", data[0])
client.close()

Modbus Protocol Specification