ModifyTags

(VTScada-Layer function. Must be called with a leading backslash.)

Description: Can be used to create, modify, or delete running tags. Replacement for StartTag for the case where persisted tags were created. See comments for more detail.
Returns: Object reference
Usage: Script Only.
Function Groups: Configuration
Related to:
Format: \ModifyTags(pSuccess, TagParameters[ , newTags, UserID, Comment, Merge, HaveLock, pErrors)
Parameters:  
pSuccess
An optional pointer to a value, which will be set to 1 on successful completion or 0 on failure.
TagParameters
Dictionary of tag parameters, each of which is also a dictionary. See examples.
NewTags
Optional. Dictionary of tag additions. Key is tag friendly name and value is tag type.
If you have a NewTags entry for a tag that already exists, then the action will be a deletion and an add of that tag. The added tag will not have the same UniqueID as the original tag, and therefore page references and history for the old tag will not be associated with the new tag,
UserID
Optional. User making change
Comment
Optional. Comment to store with changes
Merge
Optional. On update, true to retain parameters not specified in parameter dictionary, false to revert all other parameters to their defaults. Defaults to TRUE
HaveLock
Optional. If false, this module gets the working copy lock and commits changes and update tags when finished. If true, caller must have WC lock ModifyTags will not get WC lock, commit changes, or update running tags. Defaults to FALSE
pErrors

Optional output: dictionary of errors, keyed by name of tag with error, containing #MODTAGS_* error code. Defined in Code.

Constants used as error codes, returned in the pErrors dictionary parameter of ModifyTags:

Constant Value Description
#MODTAGS_BADNAME 1 Name of added tag is not allowed. Refer to tag naming rules.
#MODTAGS_BADTYPE 2 Provided type is not an existing type
#MODTAGS_MISSINGTAG 3 Attempting to modify a non-existent tag.
#MODTAGS_MISSINGPARENT 4 Attempting to add a child to a non-existing parent.

Constants used as global error codes returned in root value of ModifyTags's pErrors dictionary parameter:

Constant Value Description
#MODTAGS_NOERROR 0 No error.
#MODTAGS_TAGERROR 1 One of the errors listed in the preceding table.
#MODTAGS_NOTEDITABLE 2 Application cannot be edited at this time. (Most likely, a restart is required.)
Comments:

Some readers may have used non-persisted StartTag calls to create parent/child tag structures. Now that StartTag is obsolete, those structures should be created with the Tag Browser, not in code.

This module launches a worker module into Code so that the operation is not interrupted by this module's caller being slain. The return value of the function is a reference to this worker module. By watching for this to become invalid, you can discover when the module has finished.

ModifyTags works by modifying root tag declarations or adding overrides for child tags not defined in the root tag database. It does not modify tag type definitions.

The TagParameters dictionary is formatted as follows:

 TagParameters[FullFriendlyName] = {TheChange};
  • For tag deletion, {TheChange} is simply Invalid.
  • For a creation or update, {TheChange} is a dictionary of parameter values, keyed by parameter name.

When creating a new tag, the NewTags dictionary must have an entry specifying the tag type. If there is a tag with the given name already running, it will be deleted and the new tag will be created with a new unique ID, even if the type specified in NewTags is the same as the type of the currently-running tag. Hence, this is a way to stop a tag and create a tag having the same friendly name, but a different unique ID and possibly a different type, all in a single operation.

When updating a tag, what will happen to tag parameters that are not specified in the TagParameters dictionary will depend on the value of the Merge parameter. If TRUE (the default), then those parameters remain unchanged by the operation. If FALSE, then those parameters revert to their default, where default for a root tag is the default specified in the tag type, and the default for a child tag is the value specified by its parent's type's child tag definition record (that is, the value it would have without any root overrides). The Merge parameter has no effect on tag additions or deletions.

To set parameters to expressions, you can set metadata on individual parameter values. For example:

TagParms[TagName][ParmName] = ExpressionText;
Metadata(TagParms[TagName][ParmName], System.#EXPRESS_META) = System.#EXPRESS_REFRESH; {non-optimized expression}
Metadata(TagParms[TagName][ParmName], System.#EXPRESS_META) = System.#EXPRESS_SNAPSHOT; {optimized expression}

If HaveLock is TRUE, then when this module finishes, the memory cache of tag parameters will have been updated, and those changes will be pending to be written out to tag files and incorporated into running tags. Note that there is no guarantee that those actions have been performed. That will happen during the next commit. If HaveLock is FALSE, then it is guaranteed that all running tags affected by these changes will have been updated or stopped (whichever applies). Also, while all root tags and all child tags (whose parents are running and that the changes cause to bring into existence) will be running, it is not guaranteed that they will have run their Refresh modules. It is also not guaranteed that children of tags just started will be running yet let alone Refreshed.

Examples:

Example 1 - Modify running tags (A and B exist and are running):

TagParms = Dictionary();
NewTags   = Dictionary();

TagParms["A"] = Dictionary();
TagParms["A"]["Description"] = "Updated description1";
TagParms["A\B"] = Dictionary();
TagParms["A\B"]["Description"] = "Updated description2";

Success = Invalid;
Code\ModifyTags(&Success, TagParms, NewTags, GetUserID(), "Modify tags", TRUE, FALSE, &Errors);

Example 2 - Add child tags (Tag C exists and is running):

TagParms = Dictionary();
NewTags   = Dictionary();

NewTags["C\D"]   = "AnalogInput";
TagParms["C\D"] = Dictionary();
TagParms["C\D"]["Description"] = "New AI description";
NewTags["C\D\E"]  = "DigitalInput";
TagParms["C\D\E"] = Dictionary();
TagParms["C\D\E"]["Description"] = "New DI description";

Success = Invalid;
Code\ModifyTags(&Success, TagParms, NewTags, GetUserID(), "Add tags", TRUE, FALSE, &Errors);

Example 3 - Delete a tag (Tag C\F exists. The third parameter must be invalid. The sixth must be false.):

TagParms = Dictionary();
TagParms["C\F"] = Invalid;
Success = Invalid;
Code\ModifyTags(&Success, TagParms, Invalid, GetUserID(), "Delete Tags", FALSE, FALSE, &Errors);

Example 4 - Add a parent and a child tag (G and H do not exist):

TagParms = Dictionary();
NewTags   = Dictionary();

NewTags["G"]   = "Calculation";
TagParms["G"] = Dictionary();
TagParms["G"]["Description"] = "New Calc description";
NewTags["G\H"]   = "AnalogStatus";
TagParms["G\H"] = Dictionary();
TagParms["G\H"]["Description"] = "New AS description";

Success = Invalid;
Code\ModifyTags(&Success, TagParms, NewTags, GetUserID(), "Add tags", TRUE, FALSE, &Errors);

After ModifyTags completes, the following changes to the running tags are guaranteed:

  • A and A\B will be updated.
  • C\F will be stopped.
  • C\D and G will be running but not necessarily refreshed yet.
  • C\D\E and G\H (added tags whose parents weren't already running) will not necessarily be running yet.

If TagParms includes the deletion of a parent tag, then all TagParms and NewTags records related to the addition/modification/deletion of any children of that tag are discarded.