Smart OPC XML HDA Virtualize plugin provides ability to make virtual items in the server's address space, which values are calculated through scripts written in C#.
Directory Structure
<InstallDir> - This is the base server folder. Here is situated the starting executable of the server;
Plugins - Here are situated server plugin modules;
HdaVirtualize - An OPC XML HDA Virtualize plugin;
Bin - Contains binaries of the plugin;
AddIns - Contains plugin module addins;
Slot0 - Slot 0 of the HdaVirtualize Addin;
Slot1 - Slot 1 of the HdaVirtualize Addin;
Config - Contains configuration files of the plugin;
Scripts - Contains C# scripts (*.csx) of the virtual items;
Logs - Contains log files of the plugin;
Configuration Attributes
The Smart OPC XML HDA Virtualize plugin configuration is separated in several XML configuration files situated in <InstallDir>\HdaPlugins\HdaVirtualize\Config folder. Configuration attributes of the Smart OPC XML HDA Virtualize plugin are located in <InstallDir>\Plugins\HdaVirtualize\Config\Smart.OpcXml.Plugin.Configuration.xml file.
Example:
<?xml version="1.0"?>
<HdaVirtualizePluginConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- NLog logger name. If empty or omitted the null logger will be used instead. -->
<LoggerName>Smart.OpcXml.Plugins.Hda.HdaVirtualize</LoggerName>
<!-- Value indicating whether plugin supports HdaReadRaw. -->
<SupportHdaReadRaw>true</SupportHdaReadRaw>
<!-- Value indicating whether plugin supports HdaReadProcessed. -->
<SupportHdaReadProcessed>true</SupportHdaReadProcessed>
<!-- Value indicating whether plugin supports HdaReadAtTime. -->
<SupportHdaReadAtTime>true</SupportHdaReadAtTime>
<!-- Value indicating whether plugin supports HdaGetAggregates. -->
<SupportHdaGetAggregates>true</SupportHdaGetAggregates>
<!-- Value indicating whether plugin supports HdaGetStatus. -->
<SupportHdaGetStatus>true</SupportHdaGetStatus>
<!-- Value indicating whether plugin supports HdaBrowse. -->
<SupportHdaBrowse>true</SupportHdaBrowse>
<!-- Plugin module alias. -->
<Alias>VIRTUALIZE</Alias>
<!-- Plugin module pathSeparator used for the plugin address space items path and name. -->
<PathSeparator>.</PathSeparator>
<!-- Plugin module OriginalPathSeparator used for the plugin address space
items path and name. Original path separator is replaced with path separator. -->
<OriginalPathSeparator>.</OriginalPathSeparator>
<!-- Maximum available items to read at once via HdaReadAtTime. 0 means no restriction. -->
<MaxItemsPerHdaReadAtTime>0</MaxItemsPerHdaReadAtTime>
<!-- Maximum available items to read at once via HdaReadProcessed. 0 means no restriction. -->
<MaxItemsPerHdaReadProcessed>0</MaxItemsPerHdaReadProcessed>
<!-- Maximum available items to read at once via HdaReadRaw. 0 means no restriction. -->
<MaxItemsPerHdaReadRaw>0</MaxItemsPerHdaReadRaw>
<!-- Interval in milliseconds of estimating HDA performance counters. Value
cannot be lower than 1000ms. -->
<HdaPerformanceCountersEstimationInterval>60000</HdaPerformanceCountersEstimationInterval>
<!-- Max number of HdaReadRaw requests since last counters snapshot after that
the server will response with E_REJECTED on HdaReadRaw requests. 0 means no
limitations. -->
<MaxHdaReadRawAfterSnapshot>0</MaxHdaReadRawAfterSnapshot>
<!--Max number of HdaReadProcessed requests since last counters snapshot after
that the server will response with E_REJECTED on HdaReadProcessed requests.
0 means no limitations. -->
<MaxHdaReadProcessedAfterSnapshot>0</MaxHdaReadProcessedAfterSnapshot>
<!-- Max number of HdaReatAtTime requests since last counters snapshot after
that the server will response with E_REJECTED on HdaReadAtTime requests.
0 means no limitations. -->
<MaxHdaReadAtTimeAfterSnapshot>0</MaxHdaReadAtTimeAfterSnapshot>
<!-- Max number of HdaGetAggregates requests since last counters snapshot after
that the server will response with E_REJECTED on HdaGetAggregates requests.
0 means no limitations. -->
<MaxHdaGetAggregatesAfterSnapshot>0</MaxHdaGetAggregatesAfterSnapshot>
<!-- Max number of HdaGetStatus requests since last counters snapshot after
that the server will response with E_REJECTED on HdaGetStatus requests.
0 means no limitations. -->
<MaxHdaGetStatusAfterSnapshot>0</MaxHdaGetStatusAfterSnapshot>
<!-- Max number of HdaBrowse requests since last counters snapshot after that
the server will response with E_REJECTED on HdaBrowse requests.
0 means no limitations. -->
<MaxHdaBrowseAfterSnapshot>0</MaxHdaBrowseAfterSnapshot>
<!-- Max number of requests since last counters snapshot after that the server
will response with E_REJECTED on all requests. 0 means no limitations. -->
<MaxHdaRequestsAfterSnapshot>0</MaxHdaRequestsAfterSnapshot>
<!-- If is set to "true". DefaultFirstChanceExceptionsHandler will be attached
to the executing application domain. -->
<!-- Uncomment this to enable debug traces on first chance exceptions. Use only
for debugging purposes. -->
<!-- <DebugTraceFirstChanceExceptions>true</DebugTraceFirstChanceExceptions> -->
<!-- If is set to "true". DefaultUnhandledExceptionsHandler will be attached to
the executing application domain. -->
<!-- Uncomment this to enable debug traces on unhandled exceptions. Use only
for debugging purposes. -->
<!-- <DebugTraceUnhandledExceptions>true</DebugTraceUnhandledExceptions> -->
<!-- Interval in milliseconds to wait before to start the new add in process.
Range [10000 - 120000]ms.-->
<!-- If TcpClientChannelSocketCacheTimeout parameter in
Smart.OpcXml.Service.Configuration.xml configuration file
is not set or is 5000 ms, then this parameter should be 30000ms. If
TcpClientChannelSocketCacheTimeout is 30000ms., this parameter
must be set at the maximum of 120000ms. This is important if you choose to use
remoting proxy services OpcXmlDaRem.asmx and OpcXmlHdaRem.asmx.
But if you use only OpcXmlDa.asmx and OpcXmlHda.asmx web service, which do not
use remoting proxies, then you may set this parameter to 10000ms -->
<AddInProcessRestartWaitTime>30000</AddInProcessRestartWaitTime>
<!-- Interval in milliseconds of checking AddIn state. Value cannot be lower than 3000 ms. -->
<CheckAddInStateInterval>3000</CheckAddInStateInterval>
<!-- Memory threshold in mega bytes after that the addIn process will be
recycled. 0 means no limit.-->
<ProcessMemoryThreshold>1024</ProcessMemoryThreshold>
</HdaVirtualizePluginConfiguration>
Common Configuration Attributes of Smart OPC XML HDA Module are also valid here. We will describe here additional configuration attributes only.
[AddInProcessRestartWaitTime]
Interval in milliseconds to wait before to start the new add in process. Range [10000 - 120000] ms.
Remark: If TcpClientChannelSocketCacheTimeout parameter in
Smart.OpcXml.Service.Configuration.xml configuration file is not set
or is 5 seconds, then this parameter should be 30000ms. If
TcpClientChannelSocketCacheTimeout is 30 seconds, this parameter
must be set at the maximum of 120000ms. This is important if you
choose to use remoting proxy services OpcXmlDaRem.asmx and
OpcXmlHdaRem.asmx. But if you use only OpcXmlDa.asmx and
OpcXmlHda.asmx web service, which do not use remoting proxies, then
you may set this parameter to 10000ms.
[CheckAddInStateInterval]
Interval in milliseconds for checking AddIn's state. Value cannot be lower than 3000 ms.
[ProcessMemoryThreshold]
Memory threshold in mega bytes after that the addIn process will be recycled. 0 means no limit.
AddIn Slots
The HdaVirtualize plugin raises two separate addin process using managed add-in framework. Because of technology constraint it is not possible to raise two addin processes from the same place. That's the reason why we use slots for each addin process. The are slots situated in
<InstallDir> - This is the base server folder. Here is situated the starting executable of the server;
Plugins - Here are situated server plugin modules;
HdaVirtualize - An OPC XML HDA Virtualize plugin module;
Bin - Contains binaries of the plugin module;
AddIns - Contains plugin module addins;
Slot0 - Slot 0 of the HdaVirtualize Addin;
Slot1 - Slot 1 of the HdaVirtualize Addin;
The plugin uses the addin with the largest allocated memory to execute the scripts. When an AddIn's allocated memory reaches the threshold configured by the "ProcessMemoryThreshold" property in the configuration file, the calculations are transferred to the second AddIn and the first one is recycled.
Configuring Virtual Items
Virtual items values are estimated through scripts written in C#, situated in script files which are located in the "Scripts" folder. The recommended extension used for script files is ".csx". The recommended rule for constructing the script file name is "[Virtual item name].csx". The first thing you have to do when configuring a virtual item is to define it in the plugin's address space. The file responsible for describing the pugin's address space is named "Smart.OpcXml.AddressSpace.Elements.xml".
Example:
<HierarchicalHdaBrowseElement Name="Virtual" ItemPath="" ItemName="Virtual" IsItem="false"
HasChildren="true" >
<HierarchicalHdaBrowseElement Name="DemoItem" ItemPath="" ItemName="Virtual.DemoItem"
IsItem="true" HasChildren="false" VirtualScriptPath="Virtual.DemoItem.csx"/>
</HierarchicalHdaBrowseElement>
The first element defines a branch node which is used for grouping elements and its property "IsItem" is set to "false". Also the branch has a child, that's why the "HasChildren" property is set to "true". The second element inside defines a leaf (item) node ("IsItem" is set to "true") which is the new virtual item.
Remark: When configuring a leaf node the "HasChildren" property must
be set to "false". Respectively the leaf node must not have children in
it.
Virtual item value will be provided via script located in VirtualScriptPath ="Virtual.DemoItem.csx". Virtual script path is relative path starting from "[Plugin folder]\Config\Scripts\" pointing to where the script is located. Create new file in "[Plugin folder]\Config\Scripts" named "Virtual.DemoItem.csx". Open the file with a text editor and write the following snippet:
public HdaItemValueCollection VirtualHdaReadRaw() {
var itemId = new HdaItemIdentifier(){
ItemName = "OPC.SWP-EPKS-410./ASSETS/01/SINEWAVE.PV"
};
var result = HdaServer.HdaReadRaw(StartTime,
EndTime,
MaxValues,
IncludeBounds,
new HdaItemIdentifier[] { itemId });
return result[0];
}
public HdaItemValueCollection VirtualHdaReadProcessed() {
var itemId = new HdaItem() {
ItemName = "OPC.SWP-EPKS-410./ASSETS/01/SINEWAVE.PV",
AggregateID = Item.AggregateID
};
var result = HdaServer.HdaReadProcessed(StartTime,
EndTime,
ResampleInterval,
new HdaItem[] { itemId });
return result[0];
}
public HdaAggregate[] VirtualHdaGetAggreagates()
{
return HdaServer.HdaGetAggregates(
new HdaItemIdentifier() {
ItemName = "OPC.SWP-EPKS-410./ASSETS/01/SINEWAVE.PV"
});
}
Always you must write 3 functions:
public HdaItemValueCollection VirtualHdaReadRaw(){}
public HdaItemValueCollection VirtualHdaReadProcessed(){}
public HdaAggregate[] VirtualHdaGetAggreagates(){}
These 3 functions are mandatory regarding the classic OPC History Data Access specification. When a given function is called you have access to 9 system properties:
-
public IOpcXmlDa DaServer { get; set; }- An interface to the OPC XML Data Access part of the Smart OPC XML Server; -
public IOpcXmlHda HdaServer { get; set; }- An interface to the OPC XML History Data Access part of the Smart OPC XML Server; -
public HdaItem Item { get; set; }- Item filled with appropriate item name and path of the requested item (filled only when VirtualHdaReadProcessed is called); -
public HdaTime StartTime { get; set; }- start time of the history data access interval (filled only when VirtualHdaReadRaw or VirtualHdaReadProcessed are called); -
public HdaTime EndTime { get; set; }- end time of the history data access interval (filled only when VirtualHdaReadRaw or VirtualHdaReadProcessed are called); -
public int MaxValues { get; set; }- Maximum values to return (0 -- default). Server returns an error if you specify value greater than is supported by OPC HDA server (filled only when VirtualHdaReadRaw is called); -
public bool IncludeBounds { get; set; }- Specifies if to include bounds Start-End times of the requested history data access interval (filled only when VirtualHdaReadRaw is called); -
public decimal ResampleInterval { get; set; }- resample interval in seconds (filled only when VirtualHdaReadProcessed is called); -
public HdaItemIdentifier ItemIdentifier { get; set; }- Item filled with appropriate item name and path of the requested item (filled only when VirtualHdaReadProcessed or VirtualHdaGetAggregates are called).
Via "DaServer" variable you have full access to the 8 actions as specified in OPC XML DA Specification (Browse, Read, Write, Subscribe, SubscriptionPolledRefresh, SubscriptionCancel, GetStatus and GetProperties). Via HdaServer variable you have full access to the 6 actions as specified in OPC History Data Access specification (HdaBrowse, HdaGetAggregates, HdaGetStatus, HdaReadAtTime, HdaReadProcessed and HdaReadRaw). HdaReadAtTime is not mandatory and thus is not supported by some OPC HDA servers.
You can include a script file into other by using "@require" directive.
Example:
@require somescriptfile.csx
...
The "@require" directive is recommended to be at the beginning of the script file. Thus using "@require" you can write reusable snippets of code which you can import into other scripts for estimating values of various virtual items.
A short reference to the OPC XML HDA interface, methods and used typed you can find in appendices here.