next up previous contents
Next: Server Configuration Up: main Previous: Building OPC XML-DA Clients   Contents

Server Functionality

The PyOPC framework also enables easy and rapid creation of OPC XML-DA compliant servers. Implementing OPC servers is more complicated than creating clients, however PyOPC introduces several concepts that should greatly reduce the effort.

Most often, an OPC server will retrieve data from underlying devices or networks, such as fieldbuses. Most of these underlying technologies will also provide operations similar to OPC operations, such as reading and writing. In such a situation, the OPC XML-DA server will be similar to a proxy, which retrieves data on one side from fieldbuses or devices, reformats it and provides it to clients on the other side, such as depicted in figure 5.

Figure 5: OPC XML-DA Server as a Proxy

PyOPC introduces a server class, the XDAServer, which provides methods for each OPC operation. This class can be inherited and the methods can be overridden by custom implementations, as illustrated in figure 6.

Figure 6: Server Class Hierarchy

For instance, the class BasicXDAServer inherits from XDAServer. The BasicXDAServer class overrides certain functionality of its parent class, such as Read and Write, where it implements its own functionality. However, this is still a quite general class and is not intended for the actual server instance. Instead, another class, MyBasicXDAServer inherits from the class, which defines various attributes that define the runtime parameters for the server instance, such as ``GetStatus'', which may be set to any custom value.

This way, implementing a OPC XML-DA server with PyOPC leads to a three-level class hierarchy:

  1. The basic XDAServer class that implements general functionality, which is provided by the PyOPC framework
  2. A server-specific class that overrides certain operations to implement its custom functionality, which has to be implemented for the dedicated system
  3. The production-specific class, which defines several production specific parameters and is used for the server instance.

Listing 9 shows the code for a very basic server that inherits from the BasicXDAServer class, which enables to define several OPC items in the server instance itself. These OPC items can then be read and written by OPC clients.

\begin{lstlisting}[caption={Simple OPC XML-DA Server}
... super(MyXDAServer, self).GetStatus((IPH,inOptions,outOptions))

In line 9 some predefined OPC items are set in the server instance. These items are defined in an external module, which is imported in line 6. Moreover the MyXDAServer class defines the class attribute ``StatusInfo'' which will then be used in the OPC ``GetStatus'' operation.

Line 12-18 shows how the ``GetStatus'' operation is overridden by the inherited class. In this method, the OPC option ``Product Version'' is set to an arbitrary number between 1 and 9.

Line 17 is very important: this line calls the method of the parent class and returns the results. Python does not automatically call its parent class, this has to be done manually. However, it is mandatory in PyOPC that an overridden OPC operation has to call the method in its parent class. The reason is that this parent method fulfills several needed functionality, such as setting several other needed OPC options to maintain compatibility with the OPC XML-DA specification. The call of the superclass method has always to be done at the end of the custom method.

The above listing also shows how data such as the global options and the OPC items are passed. It is obvious that any XDAServer-based method, which represents an OPC operation, has to process parameters from the client request message and has to create several appropriate output parameters, which form the base of the response message. In PyOPC, these request and response parameters are passed from one method to another and thus also from each child to its parent method, such as shown in figure 7.

Figure 7: OPC Parameter Passing

Similar to the PyOPC-based client, the request and response messages are represented by a Python dictionary that contains the global OPC options and a list of ItemContainer objects, representing the OPC items. It can be observed in figure 7 that OPC data is passed from one method to another. All these methods require the input parameters and will set or alter certain output parameters.

Therefore it is appropriate to aggregate the input and output parameters in one Python object, which is then passed from one method to another. Therefore each PyOPC method, which represents an OPC operation, must define a Python tuple as a parameter which contains the following three objects:

  1. The Item Pair Holder (IPH), a special object that contains an input and output list of ItemContainer objects. These lists have always to be of the same length and every input ItemContainer object has a corresponding output ItemContainer object. These internal ItemContainer lists are normally not directly accessed. Instead, the ItemPairHolder object implements an ``append'' method, which can be used to append an input and output ItemContainer object. Moreover the object is iterable, which is most often needed by OPC operation methods.

    Listing 10 shows how such an ItemPairHolder can be created and managed:

    \begin{lstlisting}[caption={Creating and Managing the ItemPairHolder object}
...for inItem, outItem in IPH:
outItem.ItemPath = inItem.ItemPath

    The example listing first creates an ItemPairHolder object and appends some predefined ItemContainer objects. Then one certain attribute of the output item, the ``ItemPath'' is set to its corresponding input attribute.

  2. The input options (inOptions), a Python dictionary, which contains all global input options
  3. The output options (outOptions), a Python dictionary, which contains all global output options

next up previous contents
Next: Server Configuration Up: main Previous: Building OPC XML-DA Clients   Contents
Hermann Himmelbauer 2006-11-07