Sun. Oct 24th, 2021
Android communication with PLC over Modbus TCP/IP – Eritom.com automation

While taking a look at job affords on the freelancers platform upwork.com, I discovered one which requested to create an utility which might hook up with a PLC and retrieve information utilizing the Modbus TCP/IP protocol. So, why not. I made a decision to present it a attempt. Here is what got here out.

Used instruments

  • Schneider software program SoMachine – as PLC simulator which helps Modbus TCP/IP protocol. Also I attempted to make use of modpol – labored simply high-quality;
  • EasyModbusTCP/UDP/RTU .java – extraordinarily handy and easy-to-use open supply library from easymodbustcp.net;
  • Android Studio IDE – for android utility improvement. Other IDEs, similar to Intelli j IDE and others, are additionally appropriate.

Getting prepared

Using SoMachine I’ve created a quite simple motor management practical block. To management that block and monitor standing I’ll use two Holding Registers:

  • 40001 – Control Word
  • 40050 – Status Word

To begin motor I’ll use Holding Register 40001 bit 0 – true. If the practical block generates an error, 40001 bit 1 – true can be used to acknowledge it.

Status phrase bits:

  • 40050 bit 0 – Motor off;
  • 40050 bit 1 – Motor operating;
  • 40050 bit 2 – Fault;
  • 40050 bit 3 – Circuit breaker off;
  • 40050 bit 4 – Contact interlock change off;
Simple FB for motor management

Turning SoMachine to simulation mode.
Done – a check PLC that helps Modbus TCP/IP protocol works and since this half has no impact on the switch of the information, I cannot go into this half additional.

Android utility half

Let’s create new empty challenge – I referred to as it MBClient. In order to make use of the EasyModbJava.jar library (which you will have most likely downloaded already) it’s good to copy it into the challenge’s “..app/libs” listing. When the library seems within the Project tree of Android studio, right-click on it and choose Add As Library …. Done.

Let’s embody among the most crucial parts in a brand new challenge.

activity_main.xml (design view)

Text view of activity_main.xml:




    

    

    

    

    

    

Let’s create two new java lessons for studying and writing information – ReadFromModbus.java and WriteToModbus.java. As we’re dealing with communication over community thread which might decelerate efficiency of our utility and even throw undesirable exception, lessons should prolong AsyncTask.

ReadFromModbus.java:

package deal com.instance.mbclient;

import android.os.AsyncTask;

import de.re.easymodbus.modbusclient.ModbusShopper;

public class ReadFromModbus extends AsyncTask {
    Exception e;

    @Override
    protected String doInBackground(String... params) {
        ModbusShopper mClient = new ModbusShopper();
        String res = "";
        attempt {
            mClient.Connect(params[0], Integer.valueOf(params[1]));
            int[] enter = mClient.LearnHoldingRegisters(Integer.valueOf(params[2]), Integer.valueOf(params[3]));
            res = String.valueOf(enter[0]);

            return res;

        } catch (Exception e) {
            this.e = e;

            return null;
        }
    }

    @Override
    protected void onPostExecute(String s) {
        tremendous.onPostExecute(s);
    }
}

WriteToModbus.java:

package deal com.instance.mbclient;

import android.os.AsyncTask;

import de.re.easymodbus.modbusclient.ModbusShopper;

public class WriteToModbus extends AsyncTask{
    Exception e;

    @Override
    protected Void doInBackground(String... params) {
        ModbusShopper mClient = new ModbusShopper();
        attempt {
            mClient.Connect(params[0], Integer.valueOf(params[1]));
            mClient.WriteSingleRegister(Integer.valueOf(params[2]), Integer.valueOf(params[3]));
        } catch (Exception e) {
            this.e = e;
            return null;
        } lastly {

        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        tremendous.onPostExecute(aVoid);
    }
}

And lastly MainActivity.java:

package deal com.instance.mbclient;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.util.concurrent.ExecutionException;

public class MainActivity extends AppCompatActivity {

    non-public Handler     handler;

    public EditText     mStatusWordRes;
    public EditText     mControlWordRes;
    public TextView     mCycleReadIndication;

    public String       IP =            "x.x.x.x";      //IP of Modbus TCP server
    public String       port =          "502";          //Default Modbus TCP port
    public String       standingWord =    "50";           //Holding register 40050
    public String       managementWord =   "1";            //Holding register 40001

    public boolean      cycleRead = false;


    class CycleReadModbus implements Runnable{
        boolean allways = true;

        @Override
        public void run() {
            whereas (allways){
                attempt {
                    if (cycleRead) {
                        handler.receiveMessage(1).shipToGoal();
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException ie){
                    Log.d("debug", ie.getMessage());
                }
            }
        }
    }

    class ReplaceModbusWords extends Handler{

        @Override
        public void deal withMessage(@NonNull Message msg) {
            tremendous.deal withMessage(msg);
            if (msg.what == 1){
                readDataFromModbus();
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        tremendous.onCreate(savedInstanceState);
        setContentView(R.structure.activity_main);

        mStatusWordRes =        (EditText) discoverViewById(R.id.SW_editText);
        mControlWordRes =       (EditText) discoverViewById(R.id.CW_editText);
        mCycleReadIndication =  (TextView) discoverViewById(R.id.cycle_read_indication_textView);

        Button mReadDataOnce =  (Button) discoverViewById(R.id.read_data_once_button);
        Button mReadDataCycle = (Button) discoverViewById(R.id.cycle_read_data_button);
        Button mWriteDataToCW = (Button) discoverViewById(R.id.write_data_button);

        replaceIndication();

        mReadDataOnce.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                readDataFromModbus();
            }
        });


        mControlWordRes.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean b) {
                if (b) {
                    offCycleRead();
                } else {
                    writeDataToModbus(mControlWordRes.getText().toString());
                    onCycleRead();
                }
                replaceIndication();
            }
        });

        mWriteDataToCW.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                writeDataToModbus(mControlWordRes.getText().toString());
                mControlWordRes.clearFocus();
            }
        });

        handler = new ReplaceModbusWords();
        last Thread updaterThread = new Thread(new CycleReadModbus());
        updaterThread.begin();

        mReadDataCycle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (cycleRead){
                    cycleRead = false;
                } else {
                    cycleRead = true;
                }
                replaceIndication();
            }
        });
    }


    public void readDataFromModbus(){
        String[] paramsSW = {"","","",""};
        String[] paramsCW = {"","","",""};

        paramsSW[0] = IP;
        paramsSW[1] = port;
        paramsSW[2] = standingWord;
        paramsSW[3] = "1";          //Amount of phrases to learn

        paramsCW[0] = IP;
        paramsCW[1] = port;
        paramsCW[2] = managementWord;
        paramsCW[3] = "1";          //Amount of phrases to learn

        ReadFromModbus mReadSW = new ReadFromModbus();
        ReadFromModbus mReadCW = new ReadFromModbus();
        attempt {
            mStatusWordRes.setText(mReadSW.execute(paramsSW).get());
            mControlWordRes.setText(mReadCW.execute(paramsCW).get());
        } catch (ExecutionException e){
            System.out.println(e.getMessage());
        } catch (InterruptedException ie){
            System.out.println(ie.getMessage());
        }
    }

    public void writeDataToModbus(String worth){
        String[] paramsCW = {"","","",""};

        paramsCW[0] = IP;
        paramsCW[1] = port;
        paramsCW[2] = managementWord;
        paramsCW[3] = worth;

        WriteToModbus mWriteCW = new WriteToModbus();
        mWriteCW.execute(paramsCW);

    }


    public void offCycleRead(){
        cycleRead = false;
    }


    public void onCycleRead(){
        cycleRead = true;
    }


    public void replaceIndication(){
        if (cycleRead){
            mCycleReadIndication.setText(this.getResources().getString(R.string.cycle_read_on_label_text));
        } else {
            mCycleReadIndication.setText(this.getResources().getString(R.string.cycle_read_off_label_text));
        }
    }
}

Don’t overlook so as to add to AndroidManifest.xml web entry permission:

Done – supply recordsdata will be downloaded or cloned right here. I hope somebody will discover this fascinating and even useful.

By admin