Клиент UTGARD opc: многократное чтение нескольких элементов

Я написал следующий код, используя библиотеку Utgard OPC.

Мне нужно считывать данные с OPC-сервера каждые 15 секунд. Однако я не уверен, что это самый оптимальный способ его реализации. В моем сценарии мне требуется прочитать более 300 тегов с сервера.

Какие-либо предложения?

package opcClientSalem;
import java.util.concurrent.Executors;

import org.jinterop.dcom.common.JIException;
//import org.jinterop.dcom.core.JIVariant;
import org.openscada.opc.lib.common.ConnectionInformation;
import org.openscada.opc.lib.common.NotConnectedException;
import org.openscada.opc.lib.da.AccessBase;
import org.openscada.opc.lib.da.AddFailedException;
import org.openscada.opc.lib.da.AutoReconnectController;
import org.openscada.opc.lib.da.DataCallback;
import org.openscada.opc.lib.da.DuplicateGroupException;
import org.openscada.opc.lib.da.Item;
import org.openscada.opc.lib.da.ItemState;
import org.openscada.opc.lib.da.Server;
import org.openscada.opc.lib.da.SyncAccess;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;


public class opcClientSalem {
    public static void main(String[] args) throws Exception {
        // create connection information
        System.out.println("**********Initializing OPC Client**********");
        java.util.logging.Logger.getLogger("org.jinterop").setLevel(java.util.logging.Level.OFF);
        final ConnectionInformation ci = new ConnectionInformation("myusername","mypassword");
        ci.setHost("myhost");
        ci.setDomain("");
        ci.setProgId("Matrikon.OPC.Simulation.1");
        ci.setClsid("F8582CF2-88FB-11D0-B850-00C0F0104305");
        String itemIdArr[] = {"Random.Real8","Random.Int2"}; // This is where I would have an array of all items
        // create a new server
        final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
        AutoReconnectController controller = new AutoReconnectController(server);

        try {
            // connect to server
            System.out.println("**********Attempting to connect to OPC**********");
            controller.connect();
            System.out.println("**********Successfully connected to OPC**********");
            // add sync access, poll every 15000 ms
            final AccessBase access = new SyncAccess(server, 15000);

            while(true){
                for(final String str : itemIdArr){
                    access.addItem(str, new DataCallback() {
                        @Override
                        public void changed(Item item, ItemState state) {
                            // Building a JSON string with value recieved
                            String record = "[ {" +"\""+"name"+"\" :\""+str + "\",\""+"timestamp"+"\" :"+ state.getTimestamp().getTime().getTime()+ ",\""+"value"+"\" : "+value.replace("[", "").replace("]", "")  +",\"tags\":{\"test\":\"test1\"}} ]";

                            try {
                                // Post JSON string to my API which ingests this data
                                new opcClientSalem().restpost(record);
                            } catch (ClientProtocolException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }
                    });
                }
                // start reading
                access.bind();
                Thread.sleep(5000);
            }
            // wait a little bit

            // stop reading
            //access.unbind();
        } catch (final JIException e) {
            //System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
        }
    }

    private void restpost(String record) throws ClientProtocolException, IOException{

        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost("http://localhost/myapi/datapoints");
        StringEntity input = new StringEntity(record);
        post.setEntity(input);
        HttpResponse response = client.execute(post);
        System.out.println("Post success::"+record);
    }

}

person Arun Jose    schedule 23.08.2016    source источник
comment
с какими проблемами вы сталкиваетесь на самом деле?   -  person Scary Wombat    schedule 23.08.2016
comment
Этот код работает нормально. Я хотел знать, есть ли лучший способ запросить большое количество тегов вместо использования цикла for.   -  person Arun Jose    schedule 23.08.2016


Ответы (2)


Я не уверен, что вам нужно снова и снова добавлять элементы в группу while.

В других библиотеках (.net или собственный С++) обычно вам нужно добавлять элементы только один раз, а обратный вызов вызывается всякий раз, когда значение элемента изменяется.

В .net или C++ мы получаем глобальный обратный вызов для каждой группы, что кажется более эффективным, чем отдельные обратные вызовы для каждого элемента. Возможно, у SyncAccess есть какой-то глобальный обратный вызов, поищите его.

Итак, возможные оптимизации:

  • удалите часть while, добавьте элементы только один раз и бесконечный сон потока.
  • искать глобальный обратный вызов для всех элементов
person apr    schedule 24.08.2016
comment
Я попробую ваше предложение отказаться от цикла while, чтобы посмотреть, все ли работает. - person Arun Jose; 25.08.2016
comment
Я переместил цикл while, чтобы просто выполнить thread.sleep(5000). Оно работает. Спасибо. - person Arun Jose; 30.08.2016

В этом случае вам следует создать подписку.

person Kevin Herron    schedule 23.08.2016
comment
У вас есть ссылка или фрагмент кода о том, как настроить подписку? Я использовал только подписки с использованием OPC UA. - person Arun Jose; 23.08.2016
comment
Я ничего не знаю о библиотеке, которую вы используете, но что SyncAccess может на самом деле создавать подписку за кулисами. Я не знаю, почему у вас здесь есть цикл while (true) ... - person Kevin Herron; 23.08.2016
comment
Я только что наткнулся на AsyncAccess как на альтернативу SyncAccess. Попробую и сообщу, решило ли это мою проблему. - person Arun Jose; 23.08.2016
comment
Подписка, используемая в аварийном событии opc. Для чтения и записи данных вам необходимо создать группы, элементы и т. д. - person apr; 24.08.2016