FixQuality.g

FixQuality.g — changes point quality for OPC clients that treat bad quality as a disconnection.

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 application monitors a set of points in the "input domain" and copies
 * them to the "output domain".  If the quality of the input point is not
 * GOOD, then the script modifies the point value to -1 and the quality to
 * GOOD.  This is to handle an OPC client that treats bad quality as a
 * disconnection.
 * 
 * To configure this application, modify the class variables:
 *    domain_in = the name of the input domain
 *    domain_out = the name of the output domain
 *    value_if_bad = the value to substitute on the point if the quality is bad
 *                   If this is nil, then do no value substitution.
 */
require ("Application");

class FixQuality Application
{
    domain_in = "test";
    domain_out = "test2";
    value_if_bad = -1;
}

/* Monitor a point.  This includes creating the point if it does not exist,
 * and then creating the output domain's mirror of the point.  This function
 * also sets up an event handler to map any future changes of the point into
 * the output domain. */
method FixQuality.Monitor (ptname)
{
    local		outname, ptsym;
	
    outname = string(.domain_out, ":", ptname);
    ptname = string(.domain_in, ":", ptname);
    .OnChange(symbol(ptname), `(@self).BridgeQuality(#@ptname, #@outname));
    datahub_command(format("(create %s 1)", stringc(ptname)), 1);
    ptsym = symbol(ptname);
    if (!undefined_p(eval(ptsym)))
        .BridgeQuality(ptname, outname);
}

/* This is the function that does the work of mapping from the input domain
 * to the output domain. */
method FixQuality.BridgeQuality(ptname, outname)
{
    local		info = PointMetadata(symbol(ptname));
    local		value = info.value;
    if (info.quality != OPC_QUALITY_GOOD && .value_if_bad)
        value = .value_if_bad;
    datahub_write(outname, value, 1, OPC_QUALITY_GOOD, info.timestamp);
}

method FixQuality.MonitorDomain(domain)
{
    local		points = datahub_points(domain, nil);
    with point in points do
    {
        .Monitor(point.name);
    }
}

/* This is the mainline of the program.  You can either call .Monitor("pointname") for
 * each point, or you can call .MonitorDomain(.domain_in) to monitor all existing points
 * in the input domain.  If you choose to monitor the whole domain, you must re-run
 * this application whenever new points are added to the domain. */
method FixQuality.constructor ()
{
    .Monitor("point001");
    .Monitor("point002");
    .MonitorDomain(.domain_in);
}

/* Any code to be run when the program gets shut down. */
method FixQuality.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 (FixQuality);