Форум программистов, компьютерный форум, киберфорум
Наши страницы

АСУ ТП, промэлектроника

Войти
Регистрация
Восстановить пароль
 
 
Tyiler
48 / 48 / 2
Регистрация: 30.05.2014
Сообщений: 80
#1

OPC клиент (OPC_DA v2.05) для платформы NET - АСУ ТП

12.10.2014, 22:35. Просмотров 9317. Ответов 44
Метки нет (Все метки)

Предлагаю следующую библиотеку для обмена данными с OPC сервером в приложении NET.

Библиотека "OPC_NET" представляет OPC клиент для платформы NET и предназначена для легкого обмена с любыми OPC серверами поддерживающими стандарт OPC_DA v2.05. Основана на SDK OpcNetApi организации OPC Foundation - разработчика стандарта.
Данные для обмена объявляются в файле типа xlsx. Данные читаются и пишутся по именам заданным в этом файле.

Пример работы:

1. Заполнение таблицы сигналов

OPC клиент (OPC_DA v2.05) для платформы NET

2. Соединение с сервером
C#
1
2
3
4
5
6
7
8
  // создаем клиент
   OPC_NET.OPCclient cl = new OPC_NET.OPCclient();
 
  // объявляем переменные     
   cl.Init(@".\TableSignal.xlsx");
 
  // запрос на соединение с сервером
    int er =  cl.ConnectOpcServer(_ipAddrOPCserver, _nameOPCserver, _timeUpdDataOPCserver);
3. Читаем значения переменных:
C#
1
2
3
4
5
6
7
8
9
       bool err;
           
    bool val0 =  cl.ReadBool("enaFW", out err);
 
    int val1 =  cl.ReadInt16("driveFlt", out err);
 
    int val2 =  cl.ReadInt32("sensorFlt", out err);
 
    double val3 = cl.ReadReal("pressure", out err);
4. Пишем значения переменных:
C#
1
2
3
4
5
    bool err;
           
     cl.WriteInt16("dag", 34, out err);
 
     cl.WriteBool("sensEna", true, out err);

Скачать (исходник и мануал прилагаются):OPC_NET_RUS_V1.0.rar

PS: буду благодарен, если кто поделится этим чудом - ".NET4.0(WCF)" от OPC Foundation (https://opcfoundation.org/developer-tools/developer-kits-net-4-0-wcf). Сразу перепишу либу на новый лад.

Изменения версии 1.11:
- переделаны события изменения данных: удалены события конкретных типов и создано общее событие – содержащее информацию обо всех измененных переменных;
- в классе Items добавлены несколько методов для коллекции объектов;
- открыты перечисления для входных числовых значений;
- переименованы некоторые объекты;

Скачать (исходник и мануал прилагаются): OPC_NET_RUS_V1.11.rar

Прошу добавить в заголовок темы, а то сам тему изменить не могу.
5
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
12.10.2014, 22:35
Здравствуйте! Я подобрал для вас темы с ответами на вопрос OPC клиент (OPC_DA v2.05) для платформы NET (АСУ ТП):

Использование OPC-сервера от OPC Foundation (.NET) - АСУ ТП
Всем привет, возникла необходимость в разработке OPC DA 2.05a сервера под .NET, среди бесплатных вариантов ничего не нашел, писать...

HDA OPC клиент - АСУ ТП
Здравствуйте! У кого есть HDA OPC Client желательно с открытым кодом и подробным описанием? Или подробная инструкция по написанию...

OPC-клиент - SCADA
Здравствуйте! Посоветуйте хороший OPC-клиент какой можно взять и где?

OPC сервер для Modbus - SCADA
Добрый день. Необходима информация, если кто обладает, об архитектуре OPC серверов. Сейчас возникла потребность в создании своего сервера....

OPC-cервер для ПЛК Delta Electronics - SCADA
Добрый день! Подскажите,пожалуйста, существует ли OPC сервер для ПЛК Delta Electronics(интересует DVP20EX11R2) ? Есть ли у...

Конфигурационный файл Lectus Modbus OPC/DDE сервер для работы с Ивит-М - SCADA
Здравствуйте. Мучаюсь уже давно, поэтому прошу помощи. Если кто составлял конфиг, работающий в lectus для прибора ивит-м очень прошу...

44
vxg
Модератор
3184 / 1987 / 227
Регистрация: 13.01.2012
Сообщений: 7,680
13.10.2014, 21:23 #2
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от Tyiler Посмотреть сообщение
Предлагаю
я понимаю, что критиковать легче чем делать, но все таки:
-почему для хранения таблицы сигналов использован файл формата xlsx? если вы стремились к простоте и доступности почему не выбрали текстовый файл? вы думаете, что excel (причем старше 2007) стоит (должен стоять) на всех ПК и примитивен (распространен) как блокнот? на мой взгляд было бы неплохо дополнительно предусмотреть более примитивный альтернативный формат.
-почему данные в xlsx-файле так структурированы? разве не логично было бы сделать всего один лист и четыре столбца - имя, адрес, тип и признак чтения/записи? excel позволяет легко ориентироваться в подобном перечне не окосев от висящих по бокам "лишних" таблиц которые выглядят на мой вкус не совсем естественно. единственный минус предложенного перечня необходимость ввода типа и признака, но автоматическое заполнение успешно решает эту проблему.
-почему нельзя указать имя, адрес, тип и признак чтения/записи вручную (не при помощи таблицы сигналов, а путем вызова некой функции и передачи ей имени, адреса, типа и признака чтения/записи)? на мой взгляд было бы неплохо дополнительно предусмотреть такую возможность для тех кто хранит информацию о тегах в иных местах (специфических файлах своей программы, базах данных или внутри самой программы). в противном случае им придется генерировать xlsx-файл только потому что этого хочет библиотека, а не потому что он нужен.
-почему теги хранятся в списках? я не пишу на .net но разве там нет как минимум чего-то наподобие map (это такая штука где элементы... как бы проиндексированы и поиск как таковой не требуется)? то есть зачем библиотеке просматривать весь список пытаясь найти тег с указанным именем если это можно было бы сделать гораздо быстрее? для одного двух тегов это не сыграет роли, но если их будет больше - зачем разбрасываться ресурсами на ровном месте? если все это магическим образом делает использованный объект-список значит я просто полез не в свой огород и прошу меня извинить.
-аналогичная мысль о производительности возникает когда читается код в функции получающей обновленные данные построенный на switch ... case. наверное, реализовав перечень на базе map и просто доставая из него элемент по его имени мы получим большую скорость.
-наблюдение философского плана - концепция при которой для доступа к тегам используются имена (строки) стимулирует человека делать ошибки. потому что сделать ошибку 1001 раз написав одну и туже строку которая никак не проверяется компилятором проще простого. если вместо имени будет использоваться серверный хэндл или что-то подобное (некий идентификатор) полученный при вызове некой функции в которую передается собственно имя, то ошибок наверное будет меньше (во всяком случае в области видимости). хотя размер исходного кода при интенсивных вызовах будет конечно больше. кроме того, возможно, было бы полезным указывать при вызове подобной функции еще и клиентский хэндл для возможности быстрого доступа к тегу на клиентской стороне при обратных вызовах. на самом деле это наблюдение почти повторяет путь которым пошли разработчики стандарта OPC - там тоже используются серверный и клиентский хэндл. все это - просто мысли в слух. ваша библиотека скорее всего была создана именно что бы приземлить стандарт. или это они сами себя так приземлили при выпуске порта на .net. не знаю.
----
если что не так прошу прощения. все это не печали ради, а исключительно в целях перфекционизма
2
Tyiler
48 / 48 / 2
Регистрация: 30.05.2014
Сообщений: 80
13.10.2014, 21:30  [ТС] #3
спасибо. прислушаюсь. исправлю кое что.
1
Voland_
1448 / 951 / 91
Регистрация: 04.01.2010
Сообщений: 3,078
14.10.2014, 17:55 #4
Tyiler, Круто! я не пишу под .нет, для opc-клиента это, имхо, бесполезная фича. Но последователям такой класс явно придется по нраву.
Как уже и говорилось - древовидную структуру было бы (имхо) удобно хранить в xml - ексель не очень хорош. Ну, и понадобятся классы для вычитки тегов из OPC для быстрой подвязки к серверу.

Добавлено через 1 минуту
...скажем, вычитали все бенчи, отфильтровали по усатновленному признаку, и кладете в xml.
0
Tyiler
48 / 48 / 2
Регистрация: 30.05.2014
Сообщений: 80
21.10.2014, 20:46  [ТС] #5
Изменения версии 1.1:
- добавлена возможность объявлять переменные с помощью текст файла;
- добавлена возможность объявлять переменные с помощью xml файла;
- добавлен другой вид таблицы xlsx объявления переменных;
- добавлен класс «Items», который позволяет добавлять/удалять переменные напрямую и через xml документ, выгружать переменные в xml документ;
- изменены внутренние структуры хранения данных для более быстрого поиска.

Скачать (исходник и мануал прилагаются): OPC_NET_RUS_V1.1.rar

Прошу добавить в заголовок темы, а то сам тему изменить не могу.
2
vxg
Модератор
3184 / 1987 / 227
Регистрация: 13.01.2012
Сообщений: 7,680
21.10.2014, 22:03 #6
Цитата Сообщение от Tyiler Посмотреть сообщение
1.1
эх как широко душа развернулась)
-то что списки теперь являются словарями наверное хорошо и более естественно
-не знаю возможно ли это в дотнете, но в плюсах я наполнял бы списки абстрактными объектами
-если в списках будут абстрактные объекты не ясно зачем подписываться на события изменения данных только конкретного типа
-если в списках будут абстрактные объекты не ясно зачем в событии изменения данных анализировать тип
-наверное возврат массива изменившихся элементов был бы более производителен чем засыпание клиента кучей сообщений об изменении каждого элемента по отдельности
-не могу представить людей которые хотели бы получать изменившиеся данные в виде XML файла, но может я просто не все знаю... может народ их в какой нибудь JSON или SOAP сует транзитом... хз
-не ясно что мешает использовать в качестве типа какое-нибудь перечисление или константы вместо совершенно стерильных цифр 1 (R) и 2 (W)
-структура файлов на любителя но тут я уже не буду повторяться)
-чисто религиозный вопрос - мое понимание английского выворачивается от некоторых имен использованных в библиотеке. может я просто не в теме но
*GetDataToXml почему то хочу назвать GetDataAsXml
*GetStateConnect - GetConnectionState
*RemoveOfName - RemoveByName
*ConnectOpcServer - Connect (ведь мы и так знаем к какому объекту мы применяем данный метод и никаких других видов подключения мы вроде не предусматриваем)
*CheckInputDataAtXml - CheckXmlCfgFile (хотя в первом названии тоже вроде как можно найти смысл, хз)
0
Tyiler
48 / 48 / 2
Регистрация: 30.05.2014
Сообщений: 80
21.10.2014, 22:36  [ТС] #7
Цитата Сообщение от vxg Посмотреть сообщение
эх как широко душа развернулась
на этом она и остановится пожалуй.
Цитата Сообщение от vxg Посмотреть сообщение
зачем подписываться на события изменения данных только конкретного типа
ждем например тип bool, перем-е такого типа и получаем, привести труда не составит
Цитата Сообщение от vxg Посмотреть сообщение
наверное возврат массива изменившихся элементов
польз-лю решать, возможность предоставлена и такая. xml в этом плане лучше, чем была бы мной определенная структура, которую придется объявлять и иметь
Цитата Сообщение от vxg Посмотреть сообщение
какое-нибудь перечисление
та же причина. чтобы польз-лю не пришлось создавать это перечисление в своем проекте, лишнее.. имхо
Цитата Сообщение от vxg Посмотреть сообщение
почему то хочу назвать
...... не знаю даже что сказать. похоже вы правы. красивое именование это искусство, я им пока не владею. даже не замечаю, когда пишу, вроде кажется все норм.. может с англицким не очень, поэтому...
1
Voland_
1448 / 951 / 91
Регистрация: 04.01.2010
Сообщений: 3,078
22.10.2014, 13:02 #8
Цитата Сообщение от Tyiler Посмотреть сообщение
на этом она и остановится пожалуй.
а как же OPC HDA? )
0
EVG-1980
189 / 196 / 46
Регистрация: 11.04.2013
Сообщений: 1,078
08.12.2014, 09:22 #9
Цитата Сообщение от Tyiler Посмотреть сообщение
буду благодарен, если кто поделится этим чудом - ".NET4.0(WCF)" от OPC Foundation
Тоже буду очень благодарен если кто поделиться!

От себя добавлю пару строк:

Получаем список OPC серверов установленных на машине

Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public int GetServers(Specification spc , string host)
        {
            listView1.Clear();
            IDiscovery discovery = new OpcCom.ServerEnumerator();
            try
            {
                //Get  OPC 
                Opc.Server[] hostservers = discovery.GetAvailableServers(spc, host, null);
 
                if (hostservers != null)
                {
                    int i = 0;
                    foreach (var servers in hostservers)
                    {
                        ListViewItem lvItem = new ListViewItem();
                        lvItem.Tag = (object)i++;
                        lvItem.Text = servers.Name;
                        listView1.Items.Add(lvItem);
                    }
                }
                return hostservers.Length;
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); return 0; }
            finally { discovery.Dispose(); }
        }
//switch (comboBox2.Text)
            {
              //  case "DA 1.0a": spc = Specification.COM_DA_10; break;
              //  case "DA 2.XX": spc = Specification.COM_DA_20; break;
               // case "DA 3.00": spc = Specification.COM_DA_30; break;
              //  default: spc = Specification.COM_DA_20; break;
            }


Выколупываем тэги выбранного OPC сервера (если сервер поддерживает данные манипуляции)

Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {
             if (listView1.SelectedItems.Count > 0)
            {
               label2.Text =  listView1.SelectedItems[0].Text;
               treeView1.Nodes.Clear();
               //comboBox1.Text - host IP
               url = new Opc.URL("opcda://" + comboBox1.Text + "/" + listView1.SelectedItems[0].Text);
               try
               {
                   OpcCom.Factory fact = new OpcCom.Factory();
                   server = new Opc.Da.Server(fact, null);
                   server.Connect(url, new Opc.ConnectData(new System.Net.NetworkCredential()));
               }
               catch (Exception ex) { MessageBox.Show(ex.Message); return; }
               TreeNode node = new TreeNode(comboBox1.Text);
               node.Nodes.Add(new TreeNode(server.Name));
               filters = new BrowseFilters() { BrowseFilter = browseFilter.all };
               BrowseAddress(node.Nodes[0], null) ;// browser the root node included children BrowseElement., Process Browse listed below.
               treeView1.Nodes.Add(node);
             }
        }
 
       private void BrowseAddress(TreeNode node, BrowseElement parent)
        {// Recursive function, browse all the data items in the parent, these items are displayed in the TreeView node node.
            try
            {
                if (parent != null && parent.IsItem == true) return;// If the BrowseElement is Item, then the combination of the last stage, the recursion terminates.
                ItemIdentifier ItemID = null;// BrowseElement and Item common parent class.
                if (node.Tag != null && node.Tag.GetType() == typeof(BrowseElement))
                {// The node is BrowseElement object, rather than the root node.
                    parent = (BrowseElement)node.Tag;
                    ItemID = new ItemIdentifier(parent.ItemPath, parent.ItemName);
                }
                BrowsePosition position = null;// huge address space, you need to use this object, generally do not.
                BrowseElement[] elements = server.Browse(ItemID, filters, out position);
                if (elements != null)
                {// browse to the server server corresponding itemID elements contained.
                    foreach (BrowseElement element in elements)
                    {
                        TreeNode newnode = AddBrowseElement(node, element);// to the TreeView
                        
                        BrowseAddress(newnode, element);// recursive call
                    }
                }
            }
            catch (Exception e) { MessageBox.Show(e.Message); }
        }
 
        private TreeNode AddBrowseElement (TreeNode previou, BrowseElement element)
        {// Browse to BrowseElement object added to the TreeView.
            TreeNode node = new TreeNode (element.Name);
            node.Tag = element ;// record the BrowseElement object to the node.
            previou.Nodes.Add (node) ;// the node added to the TreeView.
            return node ;// return node, the recursive function.
        }
1
Leo28
3 / 3 / 0
Регистрация: 18.12.2014
Сообщений: 74
11.08.2015, 14:54 #10
Tyiler, здравствуйте, поюзал вашу библиотеку, на локально компе всё хорошо, а с удалённым вылетает исключение из класса библиотеки OPCclient.cs
C#
1
2
// подпис на событие изм данных
            _groupRead.DataChanged += new Opc.Da.DataChangedEventHandler(DataReadChange);
Unauthorized Access Exception Отказано в доступе. (Исключение из HRESULT: 0x80070005 (E_ACCESSDENIED))
перепроверил все настройки ОС как на клиенте так и на сервере, бесполезно((((
м.б посветит меня кто нибудь, в какую сторону ещё можно покапать???
0
Tyiler
48 / 48 / 2
Регистрация: 30.05.2014
Сообщений: 80
11.08.2015, 15:03  [ТС] #11
там в руководстве написано как настраивать для удаленного подключения, фаервол проверьте, может он не пускает. в общем настройка сети и DCOM. в программе можно не копаться.

в поисковике забейте "настройка DCOM" почитайте.
1
Leo28
3 / 3 / 0
Регистрация: 18.12.2014
Сообщений: 74
11.08.2015, 15:24 #12
Tyiler, воот, даже документацию проюзал дополнительную, суть знаете в чём, что в итоге то клиент конектится и считывает один раз, а дальше при изменении данных на сервере, он ссылается на событие DataChanged(((
я уже и группу создал и правила добавил, и DCOM везде где надо разрешил, всё перепроверил, реакции вообще ноль, а может это быть то что у меня студия express и она тупо ограничена где то в правах на запросы там или ещё что???

Добавлено через 5 минут
Tyiler, всёёёё, починил, проблема была в том что на стороне сервера в DCOM нужно было указать запуск сервера под юзером на котором клиент!!!!
0
Tyiler
48 / 48 / 2
Регистрация: 30.05.2014
Сообщений: 80
11.08.2015, 15:29  [ТС] #13
да..помню. неприятная такая штука с этим юзером.
0
ikari81
3 / 3 / 1
Регистрация: 17.05.2011
Сообщений: 224
14.10.2015, 13:01 #14
Tyiler, привет. Как доработать исходник, чтобы реализовать IOPCommon::SetClientName ?
0
Tyiler
48 / 48 / 2
Регистрация: 30.05.2014
Сообщений: 80
14.10.2015, 16:23  [ТС] #15
ну.. тут уже ничего не скажу. уже год как с контроллерами не имею дела. и орс тоже.. забыл как страшный сон.
0
14.10.2015, 16:23
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.10.2015, 16:23
Привет! Вот еще темы с ответами:

Клиент OPC DA для Quantum - C#
Добрый день всем! Мне необходимо создать клиента для обмена данными с контроллерами Quantum (Schneider Electric) через OPC DA. Опыт...

Клиент для OPC сервер Kepware и удаленное подключение - C#
Добрый день, подскажите пожалуйста. Есть маленький клиент на c#, который читает значения тегов и записывает в них значения. Сервер OPC...

Delphi8 для платформы .NET - Delphi
Видели какую лажу сделали Борландовцы в 8-ой версии?! --- http://alabal.narod.ru

Посоветуйте лабораторные для изучения C# и платформы .Net - C#
Здравствуйте дорогие друзья, хотел бы что бы вы посоветовали лабораторные для изучения C# и платформы .net в целом, почему именно...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru