C# and ABB OPC AC 800M OPC Server – Things, what I learned.

Recently I had to work with a ABB AC 800M OPC server. OPC servers has their own challenges, so I thought I will share, a few key points, what I learned.
First of all, there are few kind of OPC servers out there, and they support different ways to communicate them. Some of are supporting UA, some are only DA, AE and HDA.
The biggest mistake was, that I thought, they will work in the same way. In fact, they are not! They have the same basics of communication, even, the same code can work very well, but it leads to big
surprises.
Because at the development time, I haven’t access the same OPC server with the same control logic on it, I needed something to test my code. I found a free OPC Server from Matrikon, which was able to set a few variables, and randomly changing items. The project required client-server architecture, so I used WCF to bridge it. At the start of the project the main goal was to read variables. But surprisingly the penultimate day, got news; that my program need to be able to give control commands either. Since that time, my service was finished and tested; I didn’t want to touch it. I made a separate service, to be responsible for commanding. Sadly, at that time I was able to test it only with Matrikon OPC server, not with the ABB, which one is the production. My test went fine, and I needed only one night to rewire my program, thanks for the design logic which I chosen at the beginning. After it, at the real life test was an epic fail. As I mentioned OPC servers can behave differently. My system was able to read the data’s, but want able to control the process. At the first sight, my control service hasn’t enough privileged to connect the OPC server, but that was easy to solve. Bigger surprise was after the connection the ABB OPC server refused to accept the variables that I give them, even if they was in the correct type. Figured out, with IIS hosted WCF service, I will not able to control the production process, neither matter which kind of type conversions I use nor from the access rights of the service. Went back to the core, and changed a few things, first of all, I trashed out the IIS hosted WCF services and changed them to Windows Service hosted WCF service, finally only one service was responsible to read and write the OPC tags. That’s worked well in my test environment and also the production environment.

Finally comes a few lines of code. I used OPC .net API. I used the DA mode, so codes are related to that.
For discovering OPC servers, there can be done via ServerEnumerator, with the help of OpcEnum service, so make sure it’s running, or you will get an exception.

Opc.IDiscovery discovery = new OpcCom.ServerEnumerator ();
Opc.Server[] localServers = discovery.GetAvailableServers (Opc.Specification.COM_DA_20);
foreach (Opc.Server found in localServers)
{         
 txtServers.AppendText (string.Format ("\r\n{0}", found.Name));
}

For connecting to the server, use the Server class. It will require a Factory class, and the URL of the server. You can check the connection with the IsConnected property. In this example the URL came from the result of the discovery.

private void ConnectToServer (Opc.URL url)
{
 server = new Server (new OpcCom.Factory (), url);
 server.Connect ();
}

You can list the available items:

Opc.ItemIdentifier itemId = null;
BrowsePosition position;
BrowseFilters filters = new BrowseFilters () { BrowseFilter = browseFilter.all };
BrowseElement[] elements = server.Browse (itemId, filters, out position);
foreach (BrowseElement beItem in elements)
{ ... }

With giving a null as an initial ItemIdentifier, the server will give back its items, but be aware, it will list only the first level; items can have more child elements, check with the HasChildren property.

For change notification subscription, you need the tags, which you want to monitor.

Subscription groupRead;
SubscriptionState groupState = new SubscriptionState ();
groupState.Name = "Group1";
groupState.Active = true;
groupState.UpdateRate = updateRate;
groupState.Deadband = 0; // The minimum percentage change required to trigger a data update for an item.
groupRead = (Subscription) server.CreateSubscription (groupState);
groupRead.DataChanged += new DataChangedEventHandler (groupRead_DataChanged);

Item[] itemsYouWantToRead = new Item[n]; //n number of OPC tag
groupRead.AddItems (itemsYouWantToRead);

Although Subscription.AddItems expect an array, it’s still easier to start with a List fill the list with the items, new Item(){ ItemName = tag }; than convert it to an Array. Of course you can remove items from monitoring with the Subscription.RemoveItems, only one difference, which is waiting for an ItemResult array, but the principles are the same, you manage the items trough ItemName. When you add to the subscription, you also get an ItemResult collection, when you remove items you get an IdentifiedResult array, worth to check it.

Finally, to give work with controlled items, you need to change the related item’s value.

ItemValue testWrite = new ItemValue ();
testWrite.ItemName = itemOpcTag; 
testWrite.Value = changeValue;
List<ItemValue> itemsToWrite = new List<ItemValue> ();
itemsToWrite.Add (testWrite);
server.Write (itemsToWrite.ToArray ());

Item subscribtion or simple item read will return an ItemResult array. You can iterate through it. It’s worth check out the result. There are the Quality object, which will show “good” if the given value considered good, or will give some meaningful string, considered about the returned value. Also, worth check out the ResultId, which will start with an “E_” if there are some error happened, but usually the Quality which will provide more information. Even if you try to read a non existing tag, you will get an S_OK for ResultId, but the Quality will show, that item is not exist. It’s simple enough to use them on the ResultId.ToString() and Quality.ToString(). Although writing an item and removing from the subscription will result a different kind of array, you can still check the ResultId.
I don’t think, that I should mention here, like anywhere else, the importance of the log files! It can save you from trouble, like one case on this project. The production process was behaved irregularly, and the logs showed, that all of my commands and results was fine, just was some undocumented OPC tag, which I should give to the OPC server, but it wasn’t in the documentation, so saved our collective…

Advertisements

7 thoughts on “C# and ABB OPC AC 800M OPC Server – Things, what I learned.

  1. Renan Azevedo says:

    Hi, I can’t read a OPC item wrote by windows service in OPC Client. When I debug the code, it show all values correctly. Also, if I read the tags in same windows service by debug the values also show. Can you help me?

    • vividcode says:

      Hi, sorry for the late reply. First of all: which kind of OPC Server you use, also which API you use, to communicate with the OPC. OPC item wrote by windows service, you mean debugging from the OPC side?
      Similar things happened with me, when I communicate trough IIS hosted service, it just not worked with ABB, but it worked well with Matrikon, so its also depend from manufacturer.

      • Renan Azevedo says:

        Hi, I’m using o Graybox OPC Server for tests and OPC DA API .Net. I don’t understand de last question. Thanks for help.

  2. vividcode says:

    Hi, sorry my late answer again… I think, maybe I start to figure out… If I correctly understood the situation, you write a tag though OPC Server, but seems you cant read them from the PLC side? I met this problem, and well I not tested the solution jet, but I got some ideas, from ore experienced ones in this topic: at the PLC side different clock speed can be set up. When you write from the direction to the PLC from, it can happen, that the OPC Server acknowledge, that it received the values correctly, but the actual intended operation never reach the PLC. I got a suggestion, that if you have multiple subscriptions to the OPC server, those can have different update rate. It can cause this problem. So I set all subscription’s update timer to the same interval, but I didn’t had enough time to test it trough.
    Also have an another idea, if you check the code above, I using a synchronous write to the server. I will examine later with asynchronous write, but you can do that trough the subscription object not the server object. If I find some little time, I will post that code too.

  3. Renan Azevedo says:

    Hi, just to be clear. I can read from plc but I can’t write for it in windows service. Thanks for help

  4. Zip says:

    Did you use WCF to communicate directly to the OPC server or did you do that in the Windows Service and use a Contract on the WCFServiceHost to communicate ? I am asking because I am wondering if you sent the Opc.Da.Item back across the communications channel or just the value that was read, or written ?
    If you can show or send a small sample of that code – I would greatly appreciate it.

    • vividcode says:

      Hi! Sorry for my late reply. Had some personal issues that I needed to deal with.
      Sadly I can’t give you code samples, but I can tell you, that I didn’t directly communicate with the OPC Server. As far as I know its possible, but its not within the DA interface (not sure if I’m right, I had only this project which involved OPC communication), its for the UA interface.
      I used the Windows service to communicate with the OPC Server, and the OPC Server sent data back to the Windows Service, since its have some other responsibilities with the data received from the controls. The client(s) are communicated with the Windows Service to give control commands and receive measure data. But they receive only a filtered amount of data, which is necessary for the UI.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s