Containers, Contributors and Site Tags

A "container" is a tag that holds a collection of other tags known as "contributors". A tag may be a container for multiple contributor types, and a tag may also contribute to several different containers.

 

Site tags are a type of container. (Not all containers are site tags, but all site tags are containers.) A site tag is one that can be included in the Sites List page, such as Context tags, Polling drivers and Station tags. In order to classify a container tag as a site, the groups declaration must have at least the following line.

[ (GROUPS)
   Shared Container { We are a container tag };

 

A tag that is a container may also be a contributor at the same time (a container tag may accept values from its contributors, while in turn contributing its value to another container).

For example, each station in a given area might contribute its value to a container that calculates the value for that area, and each area container might contribute its value to a container that calculates the value for the province or region. These regional containers can also contribute their values to a container that calculates a national value.

The container uses a handle variable that lists the contributors for a given tag. There may be several handle variables defined, one for each kind of contributor possible. There is no naming restriction on handle variables, but both the contributor and container modules must know the name. A handle variable is used by three VTScada functions:

The following descriptions for container and contributor configuration show the minimum steps required to establish the relationship between the tags.

Container Configuration

For a container tag to know that it has contributors, it must declare the following modules in its PLUGINS group:

  [ (PLUGINS)
    Shared ContributorAdded   = "ContributorAdded";
    Shared ContributorDeleted = "ContributorDeleted";
  

The statement, Shared Container; is optional.

The container must also declare a variable that will hold all instances of each type of contributor tag. For example, an Analog Input may have the following contributors: a Logger tag, Script tags, and Alarm tags. These are declared as follows:

  AlarmContributors      { This is the "handle" used by the VTS code
                           to maintain a list of the alarm contributors};
  ScriptContributors     { This is the "handle" used by the VTS code
                           to maintain a list of the script contributors};
  LogContributors        { This is the "handle" used by the VTS code
                           to maintain a list of the logger contributors};

Contributor Configuration

Most code to configure a container-contributor relation between tags is located in the contributor. This is where the functions noted earlier will be used.

First, the contributor must include a parameter that is used to identify the tag to which it contributes. Using code from the VTScada Script tag as an example, this declaration will look like the following:

HookTag  <:TagField("SQL_VARCHAR(255)","Point to Attach", 3 ):> = "*Numeric" 
          { Name of the point whose scope we will launch the script within.};

All tag parameters require an enumerating constant:

  Constant #Hooktag    = 3;

You must also declare two variables; one to hold the current value of the parameter and one to hold the previous value. This allows you to write code to take any necessary steps when the user changes the selected hook tag.

  Hook                   { Instance of HookTag                    };
  OldHook                { Previous value of Hook                 };

In the Main state, you must watch for changes to the hook tag:

CustomTagMain [
   { Hook can change after Refresh has been called }
  If Valid(Hook = Scope(Root, HookTag)) != Valid(OldHook) || Hook != OldHook;
  [
    CriticalSection(
      \DeleteContributor("ScriptContributors", Invalid, Invalid, OldHook,
                          Root, Invalid);
      \AddContributor("ScriptContributors", Invalid, Invalid, Hook, 
                       Root, Invalid, Invalid, Invalid);
      OldHook = Hook;
    );
  ]

As noted in the previous code, it is the Refresh state that watches for changes to the hook tag:

Refresh [
  If 1;
  [
    IfThen (PickValid(Scope(Root, HookTag) != OldHook, TRUE),
      \DeleteContributor("ScriptContributors", Invalid, Invalid, 
                          OldHook, Root, Invalid);
      \AddContributor("ScriptContributors", Invalid, Invalid, 
                       Scope(Root, HookTag), Root, Invalid, Invalid, Invalid);
      OldHook = Scope(Root, HookTag);
    );
    Return(0);
  ]