@aryacode/dsh-engineering 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +6 -6
  3. package/cordis.patch.yml +1 -1
  4. package/entries/netlogic.js +266 -0
  5. package/entries/optix.js +13 -0
  6. package/package.json +3 -2
  7. package/vendor/optix/SKILL.md +68 -0
  8. package/vendor/optix/netlogic/SOURCE.json +12 -0
  9. package/vendor/optix/netlogic/index.json +1987 -0
  10. package/vendor/optix/netlogic/pages/accessing-project-nodes.md +113 -0
  11. package/vendor/optix/netlogic/pages/advanced-svg.md +124 -0
  12. package/vendor/optix/netlogic/pages/alarming.md +489 -0
  13. package/vendor/optix/netlogic/pages/async-tasks.md +236 -0
  14. package/vendor/optix/netlogic/pages/audit-signature.md +91 -0
  15. package/vendor/optix/netlogic/pages/colors.md +122 -0
  16. package/vendor/optix/netlogic/pages/companion-specs.md +77 -0
  17. package/vendor/optix/netlogic/pages/creating-objects.md +370 -0
  18. package/vendor/optix/netlogic/pages/database-interaction.md +437 -0
  19. package/vendor/optix/netlogic/pages/datagrids.md +123 -0
  20. package/vendor/optix/netlogic/pages/debugging-tips.md +605 -0
  21. package/vendor/optix/netlogic/pages/designtime-tags-import.md +531 -0
  22. package/vendor/optix/netlogic/pages/dialog-boxes.md +150 -0
  23. package/vendor/optix/netlogic/pages/dispatch-events.md +200 -0
  24. package/vendor/optix/netlogic/pages/dynamic-links.md +825 -0
  25. package/vendor/optix/netlogic/pages/element-access.md +1208 -0
  26. package/vendor/optix/netlogic/pages/engineering-units.md +298 -0
  27. package/vendor/optix/netlogic/pages/events.md +340 -0
  28. package/vendor/optix/netlogic/pages/execute-command.md +202 -0
  29. package/vendor/optix/netlogic/pages/fto-studio-cli.md +99 -0
  30. package/vendor/optix/netlogic/pages/good-practices.md +50 -0
  31. package/vendor/optix/netlogic/pages/information-model.md +89 -0
  32. package/vendor/optix/netlogic/pages/log-output.md +22 -0
  33. package/vendor/optix/netlogic/pages/managing-aliases.md +22 -0
  34. package/vendor/optix/netlogic/pages/manipulate-nodes.md +72 -0
  35. package/vendor/optix/netlogic/pages/mqtt.md +240 -0
  36. package/vendor/optix/netlogic/pages/netlogic-lifecycle.md +270 -0
  37. package/vendor/optix/netlogic/pages/netlogic-overview.md +155 -0
  38. package/vendor/optix/netlogic/pages/opcua.md +325 -0
  39. package/vendor/optix/netlogic/pages/plc-tags.md +219 -0
  40. package/vendor/optix/netlogic/pages/queries.md +1297 -0
  41. package/vendor/optix/netlogic/pages/random-generation.md +90 -0
  42. package/vendor/optix/netlogic/pages/recipes.md +375 -0
  43. package/vendor/optix/netlogic/pages/recipex.md +2383 -0
  44. package/vendor/optix/netlogic/pages/regex.md +15 -0
  45. package/vendor/optix/netlogic/pages/register-observers.md +346 -0
  46. package/vendor/optix/netlogic/pages/reports.md +141 -0
  47. package/vendor/optix/netlogic/pages/resource-uri.md +308 -0
  48. package/vendor/optix/netlogic/pages/runtime-tags-import.md +280 -0
  49. package/vendor/optix/netlogic/pages/serial-port.md +357 -0
  50. package/vendor/optix/netlogic/pages/sessions.md +58 -0
  51. package/vendor/optix/netlogic/pages/system-node.md +153 -0
  52. package/vendor/optix/netlogic/pages/template-library.md +127 -0
  53. package/vendor/optix/netlogic/pages/threading.md +236 -0
  54. package/vendor/optix/netlogic/pages/translations.md +417 -0
  55. package/vendor/optix/netlogic/pages/trends.md +128 -0
  56. package/vendor/optix/netlogic/pages/ui-animations.md +115 -0
  57. package/vendor/optix/netlogic/pages/users-groups.md +416 -0
  58. package/vendor/optix/netlogic/pages/variables-formatting.md +16 -0
  59. package/vendor/optix/netlogic/pages/variables-interaction.md +557 -0
  60. package/vendor/optix/netlogic/pages/variables-structure.md +155 -0
@@ -0,0 +1,236 @@
1
+ # Asynchronous tasks
2
+
3
+ Asynchronous tasks are very common when running special or long tasks that may negatively impact the overall operation. Asynchronous tasks were mostly designed to be used at Runtime. It is quite frequent to use `LongRunningTask` to run a long process without freezing the FactoryTalk Optix Studio interface even with a DesignTime NetLogic though.
4
+
5
+ > [!WARNING]
6
+ > Avoid modifying the project structure (pages, tags, etc) while asynchronous tasks are running, especially at DesignTime. This can cause unexpected behavior—for example, editing the project while a task is importing/exporting data may result in conflicts or errors.
7
+
8
+ ## General concepts about Asynchronous tasks
9
+
10
+ Standard C# language provides multiple ways to run asynchronous operations (such as the `async` modifier for some methods), these can be used in FactoryTalk Optix as long as those methods does not access any of the project structure (pages, tags, etc).
11
+
12
+ - Example:
13
+ - async method to read/write a CSV -> GOOD
14
+ - async method to read a CSV and import it into the TranslationDictionary -> BAD
15
+
16
+ ## Using FactoryTalk Optix Asynchronous tasks
17
+
18
+ These asynchronous tasks are InformationModel-safe and can be used to access project nodes without concerns
19
+
20
+ ### PeriodicTask
21
+
22
+ This kind of task allows a specific method to be run every `x` milliseconds, for example to blink a LED or to handle a watchdog.
23
+
24
+ Please note: the specified interval, is actually the delay between two consecutive runs of the method, and the operation is impacted by the length of the instruction to process. The next run is delayed until the task is completed, for example:
25
+
26
+ Having a task:
27
+ - PeriodicTask declared every 50mS
28
+ - Method run by the PeriodicTask takes 100mS to process
29
+
30
+ With this timings, the task is actually run every 150mS, as the interval is actually the delay after which the task is run again.
31
+
32
+ ```csharp
33
+ public override void Start()
34
+ {
35
+ // Creates a task that runs every second without impacting the UI
36
+ myPeriodicTask = new PeriodicTask(IncrementVariable, 1000, LogicObject);
37
+ myPeriodicTask.Start();
38
+ }
39
+
40
+ public override void Stop()
41
+ {
42
+ // When the NetLogic is disposed, kill the task too
43
+ myPeriodicTask?.Dispose();
44
+ }
45
+
46
+ private void IncrementVariable()
47
+ {
48
+ // Action to be run every tick of the periodic task
49
+ …
50
+ }
51
+
52
+ private PeriodicTask myPeriodicTask;
53
+ ```
54
+
55
+ ### DelayedTask
56
+
57
+ This kind of task will trigger a method after `x` milliseconds it is called, this can be useful for example to hide a toast notification after some time
58
+
59
+ ```csharp
60
+ public override void Start()
61
+ {
62
+ // Create an action that is run after 10s the page is loaded
63
+ // this could also be a method called by a button or any trigger
64
+ myDelayedTask = new DelayedTask(ResetLabelText, 10000, LogicObject);
65
+ myDelayedTask.Start();
66
+ }
67
+
68
+ public override void Stop()
69
+ {
70
+ // Make sure to dispose the task when the NetLogic is stopped
71
+ myDelayedTask?.Dispose();
72
+ }
73
+
74
+ private void ResetLabelText()
75
+ {
76
+ // Action to be run after the delay
77
+ …
78
+ }
79
+
80
+ private DelayedTask myDelayedTask;
81
+ ```
82
+
83
+ ### LongRunningTask
84
+
85
+ This is the most similar approach to the `async` modifier of the standard C# scripting, it allows to create a dedicated thread and run it without affecting the main code operation.
86
+ An `async` modifier can also be used, but an async method **cannot** access any project node (it may cause concurrency issues), in such cases, use a LongRunningTask instead.
87
+
88
+ ```csharp
89
+ class public override void Start()
90
+ {
91
+ // Create a dedicated thread to run a long or demanding process
92
+ // Without stopping the FactoryTalk Optix Runtime or Studio
93
+ myLongRunningTask = new LongRunningTask(ProcessCSVFile, LogicObject);
94
+ myLongRunningTask.Start();
95
+ }
96
+
97
+ public override void Stop()
98
+ {
99
+ // Make sure to dispose the thread once the NetLogic is stopped
100
+ myLongRunningTask?.Dispose();
101
+ }
102
+
103
+ private void ProcessCsvFile(LongRunningTask task)
104
+ {
105
+ // Process that takes long time to be run
106
+ …
107
+ }
108
+
109
+ private LongRunningTask myLongRunningTask;
110
+ ```
111
+
112
+ #### Passing arguments to a LongRunningTask
113
+
114
+ An overload of the LongRunningTask constructor accepts a task and an object, the task can be used to check if a cancellation was requested, while the object can be used to pass arguments to the thread that is being generated
115
+
116
+ ```csharp
117
+ [ExportMethod]
118
+ public void StartExam(bool free, string clientID = "", string examCode = "")
119
+ {
120
+ Log.Debug(examCode == "" ? "ExamLogic.StartExam" : "ExamLogic.StartExamCertification", "Starting exam");
121
+ startExamTask?.Dispose();
122
+ var argumentsObject = new StartExamParameters { isFree = free, clientID = clientID, examCode = examCode };
123
+ startExamTask = new LongRunningTask(StartExamMethod, argumentsObject, LogicObject);
124
+ startExamTask.Start();
125
+ Log.Debug(examCode == "" ? "ExamLogic.StartExam" : "ExamLogic.StartExamCertification", "Leaving method");
126
+ }
127
+
128
+ private void StartExamMethod(LongRunningTask task, object examParameters)
129
+ {
130
+ // Get the parameters
131
+ var argumentsObject = (StartExamParameters)examParameters;
132
+ string clientID = argumentsObject.clientID;
133
+ string examCode = argumentsObject.examCode;
134
+ bool free = argumentsObject.isFree;
135
+ // Do other stuff
136
+ // ...
137
+ }
138
+
139
+ private sealed class StartExamParameters
140
+ {
141
+ public bool isFree;
142
+ public string clientID;
143
+ public string examCode;
144
+ }
145
+
146
+ private LongRunningTask startExamTask = null;
147
+ ```
148
+
149
+ ## Some general notes on asynchronous tasks
150
+
151
+ ### Cancellation token
152
+
153
+ When a task is called asynchronously (especially in LongRunningTask), then the method itself should check if a cancellation request is pending (see [documentation here](https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/task-cancellation)) and act accordingly, for example:
154
+
155
+ ```csharp
156
+ public class LongRunningLogic : BaseNetLogic
157
+ {
158
+ public override void Start()
159
+ {
160
+ // Create the new LongRunningTask and run it
161
+ myTask = new LongRunningTask(MyMethod, LogicObject);
162
+ myTask.Start();
163
+ }
164
+
165
+ public override void Stop()
166
+ {
167
+ // Request a cancellation event to the async task
168
+ myTask?.Dispose();
169
+ }
170
+
171
+ public void MyMethod()
172
+ {
173
+ for (int i = 0; i < 1000; i++)
174
+ {
175
+ // Check if the somebody requested to dispose this task
176
+ if (myTask.IsCancellationRequested)
177
+ return;
178
+ // Do some work here
179
+ Thread.Sleep(1000);
180
+ Owner.Get<Led>("LED1").Active = !Owner.Get<Led>("LED1").Active;
181
+ }
182
+ }
183
+
184
+ private LongRunningTask myTask;
185
+ }
186
+ ```
187
+
188
+ ### Check if a task is running
189
+
190
+ > [!WARNING]
191
+ > This is a non-public API (accessed using C# reflections) and may be subject to changes, please refer to the official documentation to access the publicly available APIs which are guaranteed to be maintained.
192
+
193
+ ```csharp
194
+ [ExportMethod]
195
+ public void DoStuff()
196
+ {
197
+ // Initialize the LongRunningTask
198
+ var myTask = new LongRunningTask(MyMethod, LogicObject);
199
+
200
+ // Do some stuff
201
+
202
+ // Check if the task is still running
203
+ while (IsTaskRunning(task))
204
+ {
205
+ Log.Info("The task is still running...");
206
+ Thread.Sleep(100);
207
+ }
208
+ }
209
+
210
+ private void MyMethod(LongRunningTask task)
211
+ {
212
+ // Do some work
213
+ throw new NotImplementedException();
214
+ }
215
+
216
+ private static bool IsTaskRunning(LongRunningTask task)
217
+ {
218
+ // Get the type of the LongRunningTask
219
+ Type taskType = task.GetType();
220
+
221
+ // Get the FieldInfo object for the isRunning field
222
+ FieldInfo isRunningField = taskType.GetField("isRunning", BindingFlags.NonPublic | BindingFlags.Instance);
223
+
224
+ // Check if the field was found
225
+ if (isRunningField != null)
226
+ {
227
+ // Get the value of the isRunning field
228
+ bool isRunning = (bool) isRunningField.GetValue(task);
229
+ return isRunning;
230
+ }
231
+ else
232
+ {
233
+ throw new InvalidOperationException("The isRunning field was not found on the LongRunningTask type.");
234
+ }
235
+ }
236
+ ```
@@ -0,0 +1,91 @@
1
+ # Audit Signature (CFR21 workflow)
2
+
3
+ The Audit Signature is a special type of object that can be added to any variable in FactoryTalk Optix, it allows to track the changes on the variable and who made those changes, this is specially useful for CFR21 compliance.
4
+
5
+ The following APIs are intended to be used at DesignTime to prepare the InformationModel with the necessary Audit Signatures.
6
+
7
+ ## Add signature to a variable
8
+
9
+ ```csharp
10
+ [ExportMethod]
11
+ public void AddSignatureToVariable()
12
+ {
13
+ var sourceVarPointer = LogicObject.GetVariable("SourceVariable") ?? throw new ArgumentException("Cannot find source variable");
14
+ var sourceVar = InformationModel.GetVariable(sourceVarPointer.Value) ?? throw new ArgumentException("Cannot find source variable");
15
+ // Create the audit variable
16
+ var sourceVar = InformationModel.Make<AuditInfo>("AuditSigning Signature");
17
+ sourceVar.Add(auditVar);
18
+ }
19
+ ```
20
+
21
+ ## Add signature on all bits of a word
22
+
23
+ ```csharp
24
+ [ExportMethod]
25
+ public void CreateAuditOnVariableSingleBits()
26
+ {
27
+ // Check if InputVariable is populated
28
+ var sourceVarPointer = LogicObject.GetVariable("SourceVariable") ?? throw new ArgumentException("Cannot find source variable");
29
+ var sourceVar = InformationModel.GetVariable(sourceVarPointer.Value) ?? throw new ArgumentException("Cannot find source variable");
30
+
31
+ // Check if TargetFolder is populated
32
+ var targetFolderPointer = LogicObject.GetVariable("TargetFolder") ?? throw new ArgumentException("Cannot find target folder");
33
+ var targetFolder = InformationModel.Get<Folder>(targetFolderPointer.Value) ?? throw new ArgumentException("Cannot find target folder");
34
+
35
+ // Prepare object for the method
36
+ var methodArguments = new object[] { sourceVar, targetFolder };
37
+
38
+ // Run the method in a separate thread
39
+ var myTask = new LongRunningTask(CreateSingleBits, methodArguments, LogicObject);
40
+ myTask.Start();
41
+ }
42
+
43
+ private void CreateSingleBits(LongRunningTask task, object methodArgumentsObj)
44
+ {
45
+ // Extract the method arguments
46
+ var methodArguments = (object[]) methodArgumentsObj;
47
+ var sourceVar = (IUAVariable) methodArguments[0];
48
+ var targetFolder = (Folder) methodArguments[1];
49
+
50
+ // Variable to store the number of bits
51
+ var numberOfBits = 0;
52
+
53
+ // Get the type of the source variable. Add new datatypes if needed
54
+ if (sourceVar.DataType == OpcUa.DataTypes.Int32 || sourceVar.DataType == OpcUa.DataTypes.UInt32)
55
+ numberOfBits = 32;
56
+ else if (sourceVar.DataType == OpcUa.DataTypes.Int16 || sourceVar.DataType == OpcUa.DataTypes.UInt16)
57
+ numberOfBits = 16;
58
+ else if (sourceVar.DataType == OpcUa.DataTypes.Float)
59
+ numberOfBits = 32;
60
+ else if (sourceVar.DataType == OpcUa.DataTypes.Double)
61
+ numberOfBits = 64;
62
+ else
63
+ throw new ArgumentException("Unsupported data type");
64
+
65
+ // Create the variable for each bit and add the auditing
66
+ for (int i = 0; i < numberOfBits; i++)
67
+ {
68
+ // Create the new variable
69
+ var newVariable = InformationModel.MakeVariable($"{sourceVar.BrowseName}_Bit{i}", OpcUa.DataTypes.Boolean);
70
+ newVariable.SetDynamicLink(sourceVar, DynamicLinkMode.ReadWrite);
71
+
72
+ // Modify the dynamic link to read only the bit using HasDynamicLink reference
73
+ var dynamicLinkVariable = newVariable.Refs.GetVariable(FTOptix.CoreBase.ReferenceTypes.HasDynamicLink) as IUAVariable;
74
+ if (dynamicLinkVariable != null)
75
+ {
76
+ dynamicLinkVariable.Value = (string)dynamicLinkVariable.Value + $".{i}";
77
+ }
78
+
79
+ // Create the audit variable
80
+ var auditVar = InformationModel.Make<AuditInfo>("AuditSigning Signature");
81
+ newVariable.Add(auditVar);
82
+
83
+ // Check if the variable already exists and delete it
84
+ if (targetFolder.Children.OfType<IUAVariable>().Any(v => v.BrowseName == newVariable.BrowseName))
85
+ targetFolder.Get(newVariable.BrowseName).Delete();
86
+
87
+ // Add the variable to the target folder
88
+ targetFolder.Add(newVariable);
89
+ }
90
+ }
91
+ ```
@@ -0,0 +1,122 @@
1
+ # Colors
2
+
3
+ FactoryTalk Optix allows you to set colors on UI objects (such as `Led`, `Rectangle`, `Panel`, etc.) using the `Color` struct. You can assign colors using pre-defined named colors or create custom colors with specific RGB/ARGB values.
4
+
5
+ ## The Color Struct
6
+
7
+ The `Color` struct has the following properties:
8
+ - `A` (byte) - Alpha channel (transparency): 0 = fully transparent, 255 = fully opaque
9
+ - `R` (byte) - Red channel: 0-255
10
+ - `G` (byte) - Green channel: 0-255
11
+ - `B` (byte) - Blue channel: 0-255
12
+ - `ARGB` (uint) - Combined ARGB value as a single 32-bit unsigned integer
13
+
14
+ ## Creating Colors
15
+
16
+ ### Using Pre-defined Named Colors
17
+
18
+ FT Optix provides hundreds of named colors through the `Colors` static class, such as:
19
+ - `Colors.Red`
20
+ - `Colors.Blue`
21
+ - `Colors.Green`
22
+ - `Colors.Goldenrod`
23
+ - `Colors.Cyan`
24
+ - `Colors.Black`
25
+ - And many more...
26
+
27
+ ```csharp
28
+ // Create a LED widget
29
+ var ledWidget = InformationModel.Make<Led>("statusIndicator");
30
+
31
+ // Set the LED color using a pre-defined named color
32
+ ledWidget.Color = Colors.Red;
33
+
34
+ // Add the LED to your UI
35
+ ...
36
+ ```
37
+
38
+ ### Using ARGB Constructor (Explicit Bytes)
39
+
40
+ Create a custom color by specifying the Alpha, Red, Green, and Blue channels as individual bytes:
41
+
42
+ ```csharp
43
+ // Create a LED widget
44
+ var ledWidget = InformationModel.Make<Led>("statusIndicator");
45
+
46
+ // Create a custom color: semi-transparent orange
47
+ // Parameters: (Alpha, Red, Green, Blue)
48
+ // Alpha = 0xff (fully opaque), Red = 0xff, Green = 0xaa, Blue = 0xbb
49
+ var customOrange = new Color(0xff, 0xff, 0xaa, 0xbb);
50
+
51
+ // Assign the custom color to the LED
52
+ ledWidget.Color = customOrange;
53
+
54
+ // Add the LED to your UI
55
+ ...
56
+ ```
57
+
58
+ ### Using ARGB Constructor (Hex Value)
59
+
60
+ Create a custom color by providing a 32-bit ARGB value as a hex number:
61
+
62
+ ```csharp
63
+ // Create a LED widget
64
+ var ledWidget = InformationModel.Make<Led>("statusIndicator");
65
+
66
+ // Create a semi-transparent blue color using a 32-bit ARGB hex value
67
+ // Format: 0xAARRGGBB (AA=Alpha, RR=Red, GG=Green, BB=Blue)
68
+ // 0x80 = 128 (50% transparent), 0x00=Red, 0x00=Green, 0xff=Blue
69
+ var semiTransparentBlue = new Color(0x800000ff);
70
+
71
+ // Assign the custom color to the LED
72
+ ledWidget.Color = semiTransparentBlue;
73
+
74
+ // Add the LED to your UI
75
+ ...
76
+ ```
77
+
78
+ ### Using System.Drawing.Color
79
+
80
+ You can convert .NET's standard `System.Drawing.Color` to FT Optix `Color` using the `ToArgb()` method:
81
+
82
+ ```csharp
83
+ // Create a LED widget
84
+ var ledWidget = InformationModel.Make<Led>("statusIndicator");
85
+
86
+ // Convert a System.Drawing.Color to FT Optix Color
87
+ // Goldenrod is a pre-defined System.Drawing color
88
+ var systemGoldenrod = System.Drawing.Color.Goldenrod;
89
+ var goldenrodColor = new Color(systemGoldenrod.ToArgb());
90
+
91
+ // Assign the color to the LED
92
+ ledWidget.Color = goldenrodColor;
93
+
94
+ // Add the LED to your UI
95
+ ...
96
+ ```
97
+
98
+ ## Complete Example
99
+
100
+ ```csharp
101
+ [ExportMethod]
102
+ public void SetupStatusLights()
103
+ {
104
+ // Create three status indicator LEDs
105
+ var operationalLed = InformationModel.Make<Led>("operationalIndicator");
106
+ var warningLed = InformationModel.Make<Led>("warningIndicator");
107
+ var errorLed = InformationModel.Make<Led>("errorIndicator");
108
+
109
+ // Use pre-defined colors for standard status states
110
+ operationalLed.Color = Colors.Green;
111
+ warningLed.Color = Colors.Yellow;
112
+ errorLed.Color = Colors.Red;
113
+
114
+ // Create a custom semi-transparent overlay color
115
+ var overlayColor = new Color(0x80, 0xff, 0xff, 0xff); // 50% transparent white
116
+
117
+ // Add the LEDs to your UI panel
118
+ Owner.Add(operationalLed);
119
+ Owner.Add(warningLed);
120
+ Owner.Add(errorLed);
121
+ }
122
+ ```
@@ -0,0 +1,77 @@
1
+ # Companion Specifications
2
+
3
+ ## Load Companion Specifications
4
+
5
+ - Companion Specifications files can be downloaded from [https://github.com/OPCFoundation/UA-Nodeset](https://github.com/OPCFoundation/UA-Nodeset)
6
+ - Add them to FactoryTalk Optix in one of these paths (make sure to replace your username or the proper FactoryTalk Optix setup folder):
7
+ - `C:\Users\<username>\Documents\Rockwell Automation\FactoryTalk Optix\CompanionSpecifications`
8
+ - `C:\Program Files\Rockwell Automation\FactoryTalk Optix\Studio <version number>\CompanionSpecifications`
9
+ - Restart the IDE after adding files to one of those paths to load new files
10
+ - Check the FactoryTalk Optix output if any error was reported after loading the files
11
+
12
+ > [!NOTE]
13
+ > Companion specifications can only be loaded at design time, so the XML files need to be added before starting the IDE.
14
+
15
+ ## Create an instance of a Companion Specs type
16
+
17
+ Please make sure the proper XML file was added to FactoryTalk Optix before starting the script
18
+
19
+ We will load an instance of the BlockType object from the DI specifications, the XML relevant part is:
20
+
21
+ ```xml
22
+ <?xml version="1.0" encoding="utf-8"?>
23
+ <UANodeSet LastModified="2023-04-13T14:49:52.318Z" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd" xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns:si="http://www.siemens.com/OPCUA/2017/SimaticNodeSetExtensions" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:s1="http://opcfoundation.org/UA/Machinery/ProcessValues/Types.xsd" xmlns:s2="http://opcfoundation.org/UA/PADIM/Types.xsd" xmlns:ua="http://unifiedautomation.com/Configuration/NodeSet.xsd">
24
+ <NamespaceUris>
25
+ <Uri>http://opcfoundation.org/UA/DI/</Uri>
26
+ </NamespaceUris>
27
+
28
+ ...
29
+
30
+ <UAObjectType IsAbstract="true" NodeId="ns=1;i=1003" BrowseName="1:BlockType">
31
+ <DisplayName>BlockType</DisplayName>
32
+ <Description>Adds the concept of Blocks needed for block-oriented FieldDevices</Description>
33
+ <Documentation>https://reference.opcfoundation.org/v105/DI/v103/docs/4.11</Documentation>
34
+ <References>
35
+ <Reference ReferenceType="HasSubtype" IsForward="false">ns=1;i=1001</Reference>
36
+ <Reference ReferenceType="HasProperty">ns=1;i=6009</Reference>
37
+ <Reference ReferenceType="HasProperty">ns=1;i=6010</Reference>
38
+ <Reference ReferenceType="HasProperty">ns=1;i=6011</Reference>
39
+ <Reference ReferenceType="HasProperty">ns=1;i=6012</Reference>
40
+ <Reference ReferenceType="HasProperty">ns=1;i=6013</Reference>
41
+ </References>
42
+ </UAObjectType>
43
+
44
+ ...
45
+ ```
46
+
47
+ From the XML we can see that the numeric identifier for the BlockType is `1003`, now in FactoryTalk Optix we need to read the NameSpaceIndex. We will also need the NamespaceUri for that CompanionSpecs, in this case is `http://opcfoundation.org/UA/DI/`
48
+
49
+ ```csharp
50
+ [ExportMethod]
51
+ public void CreateCompanionSpecsInstance()
52
+ {
53
+ Log.Info("Create Companion Specs NetLogic", "Searching NameSpaceIndex for companion spec");
54
+ // Get the NameSpaceIndex URI from the XML file
55
+ var nameSpaceIndex = LogicObject.Context.GetNamespaceIndex("http://opcfoundation.org/UA/DI/");
56
+ if (nameSpaceIndex == -1 || nameSpaceIndex == null)
57
+ {
58
+ Log.Error("Create Companion Specs NetLogic", "NameSpaceIndex not found, make sure the CompanionSpecification was properly loaded");
59
+ return;
60
+ }
61
+ else
62
+ {
63
+ Log.Info("Create Companion Specs NetLogic", "NameSpaceIndex found: " + nameSpaceIndex);
64
+ }
65
+ // The ID of the Type we want to add is 1003 - we can get this value from the specs XML file
66
+ var companionSpecsTypeNodeId = new NodeId(nameSpaceIndex, 1003);
67
+ // Create an instance of the element
68
+ Log.Info("Create Companion Specs NetLogic", "Type definition NodeId: " + companionSpecsTypeNodeId);
69
+ var instanceName = InformationModel.Get(companionSpecsTypeNodeId).BrowseName + "Instance";
70
+ var companionSpecsInstance = InformationModel.MakeObject(instanceName, companionSpecsTypeNodeId);
71
+ Project.Current.Get($"Model/{instanceName}")?.Delete();
72
+ // Optional, set a value to a children variable set as "optional" in the CompanionSpecs
73
+ // companionSpecsInstance.GetOrCreateVariable("RevisionCounter").Value = 100;
74
+ Project.Current.Get("Model").Add(companionSpecsInstance);
75
+ Log.Info("Create Companion Specs NetLogic", $"Companion Specs instance \"{instanceName}\" created and added to the model");
76
+ }
77
+ ```