TagMonitor.g

TagMonitor.g — monitors DataHub points for changes in quality or failure to change value.

Code

[Note]

The code for this and other example scripts can be found in the DataHub distribution archive, typically at one of these locations:

    C:\Program Files\Cogent\OPC DataHub\scripts\

    C:\Program Files\Cogent\Cascade DataHub\scripts\

Please refer to Section 3.1, “How to Run a Script” for more information on using scripts.

/*
 * This script monitors tags (or DataHub points) for two conditions:
 *
 * 1) change of quality
 * 2) failure to change within a time period
 *
 * For each of these, the script creates synthetic points (the "target")
 * that hold the result of monitoring the watch points.  Email and
 * database events can then be triggered from the synthetic points.
 *
 * You can modify the constructor function in this script to change the
 * point names, or to add additional watch conditions as needed.
 */

require ("Application");

class TagMonitor Application
{
}

/*
 * Set up a watch tag and a target tag such that the quality of the
 * watch tag is copied into the value of the target tag.
 */
method TagMonitor.copyQuality(poll_seconds, watch, target)
{
    // Ensure that the input and output tags exist.
    datahub_command(format("(create %s 1)", stringc(watch)), 1);
    datahub_command(format("(create %s 1)", stringc(target)), 1);
	
    // Periodically copy the quality of the watch point into the value of the target
    .TimerEvery(poll_seconds, `set(#@target, PointMetadata(#@watch).quality));
}

/*
 * Set up a watch tag, a target tag and a time such that the target tag
 * will be set to 1 if the watch tag has changed within the timer period,
 * or zero if the watch tag has not changed within the time period.  The
 * time period is specified by dead_seconds, which may be fractional.
 */
method TagMonitor.copyChangeStatus(dead_seconds, watch, target)
{
    // Ensure that the input and output tags exist.
    datahub_command(format("(create %s 1)", stringc(watch)), 1);
    datahub_command(format("(create %s 1)", stringc(target)), 1);
	
    // Start the watch point off as having changed
    setprop(watch, #has_changed, t);
	
    // Whenever the watch point changes, set its property "has_changed" to t.
    .OnChange(watch, `(@self).watchHasChanged(#@watch, #@target));
    .TimerEvery(dead_seconds, `(@self).checkChange(#@watch, #@target));
}

/*
 * A callback function that checks for a change in a point and puts a 1 or 0
 * into the target.  Reset the changed flag to zero.
 */
method TagMonitor.checkChange(watch, target)
{
    set(target, getprop(watch, #has_changed) ? 1 : 0);
    setprop(watch, #has_changed, nil);
}

/*
 * A callback whenever a change watch point changes.  We use this to change from
 * 0 to 1 as soon as we see a change in a watch point instead of waiting for the
 * poll delay.
 */
method TagMonitor.watchHasChanged(watch, target)
{
    setprop(watch, #has_changed, t);
    set(target, 1);
}

/* Write the 'main line' of the program here.
 *
 * As written, the points to watch for quality and change, as well as the
 * target points to modify, are all in the "default" domain, as follows:
 *
 * Point to watch for quality:  default:quality_watch
 * Point to watch for change:   default:change_watch
 * Target point for quality:    default:quality_target
 * Target point for change:     default:change_target
 *
 * You can change these to different domain and point names.  Also, you can
 * add any number of other points to monitor quality and change, following
 * the same syntax.
 *
 * The first argument of .copyQuality is the poll rate in seconds on the
 * quality of the point.  The first argument of .copyChangeStatus is the
 * number of "dead" seconds to wait for a change, before notifiying of
 * a failure.  
 */
method TagMonitor.constructor ()
{
    .copyQuality(1, #$default:quality_watch, #$default:quality_target);
    .copyChangeStatus(5, #$default:change_watch, #$default:change_target);
}

/* Any code to be run when the program gets shut down. */
method TagMonitor.destructor ()
{
}

/* Start the program by instantiating the class.  If your
 * constructor code does not create a persistent reference to
 * the instance (self), then it will be destroyed by the
 * garbage collector soon after creation.  If you do not want
 * this to happen, assign the instance to a global variable, or
 * create a static data member in your class to which you assign
 * 'self' during the construction process.  ApplicationSingleton()
 * does this for you automatically. */
ApplicationSingleton (TagMonitor);