@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,370 @@
1
+ # Creating elements
2
+
3
+ Graphical elements can be added both at design time and at runtime, but some differences exist in the syntax and in the available types, as described in the sections below.
4
+
5
+ When creating UI elements at runtime, please read the [NetLogic Lifecycle](./netlogic-lifecycle.md) chapter to understand when and how to create elements in a safe way without risking to create concurrency issues or performance problems.
6
+
7
+ ## UI Elements
8
+
9
+ ### Add an element to the project
10
+
11
+ Native types are the one predefined in FTOptix, these are the most simple to create and add anywhere in the project. These types exists both at RunTime and DesignTime, so the syntax does not change depending on the NetLogic type.
12
+
13
+ ```csharp
14
+ // Create a new Panel called "MyNewPanelName"
15
+ var newPanel = InformationModel.Make<Panel>("MyNewPanelName");
16
+ // Set some properties (if needed)
17
+ newPanel.Width = 300.0;
18
+ newPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
19
+ // Add it to "UI/Screens/Screen1"
20
+ Project.Current.Get("UI/Screens/Screen1").Add(newPanel);
21
+ ```
22
+
23
+ #### Make it faster
24
+
25
+ When you need to create a lot of element in a short time (such in a `for` loop), adding each element to the page every time is not recommended as multiple async request are made to FTOptix APIs and some concurrency issues may appear, in this case we suggest to create the whole model in RAM and then add it to the page only when the whole structure is defined
26
+
27
+ ```csharp
28
+ // Create a container for the new elements
29
+ var tempPanel = InformationModel.Make<Panel>("MotorsGroup");
30
+ // Set the container to fill the parent item
31
+ tempPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
32
+ tempPanel.VerticalAlignment = VerticalAlignment.Stretch;
33
+ // Create the 100 motors
34
+ for (i = 0; i < 100; i++) {
35
+ // Create the new Panel widget
36
+ var newPanel = InformationModel.Make<Panel>("MyMotor" + i.ToString());
37
+ // Set some properties
38
+ newPanel.Width = 300.0;
39
+ newPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
40
+ // Add the Panel to the new container
41
+ tempPanel.Add(newPanel);
42
+ }
43
+ // Finally, add the new container to the Screen (with all the elements)
44
+ Project.Current.Get("UI/Screens/Screen1").Add(tempPanel);
45
+ ```
46
+
47
+ ### `Panel` Assigning the value of Move Target property
48
+
49
+ The Move target property is an optional extra, so it must be materialized before any value can be set. When creating a Panel from NetLogic, this step is mandatory.
50
+ This property may be *None* or *Self*. As this property is a **NodePointer**, you must create a dynamicLink with value **..@NodeId** if you want to set **Self**, otherwise you must simply remove the DynamicLink to set **None**.
51
+
52
+ ```csharp
53
+ private void StuffMakePanelUIObject(IUANode panelOwner, string panelName, int width, int height, bool moveTargetSelf)
54
+ {
55
+ // Get the owner of the Panel (in case we want to use the Panel to move the parent element)
56
+ Panel panel = panelOwner.Get(panelName) as Panel;
57
+ // Make sure the Panel exists
58
+ if (panel == null)
59
+ {
60
+ panel = InformationModel.MakeObject<Panel>(panelName);
61
+ panelOwner.Add(panel);
62
+ }
63
+ // Set some properties
64
+ panel.Height = height;
65
+ panel.Width = width;
66
+ // Access the optional variable value
67
+ IUAVariable moveTarget = panel.GetOrCreateVariable("MoveTarget");
68
+ // Prepare the DynamicLink
69
+ DynamicLink moveTargetLink = moveTarget?.Refs.GetVariable(FTOptix.CoreBase.ReferenceTypes.HasDynamicLink) as DynamicLink;
70
+ if (moveTarget != null && moveTargetSelf)
71
+ {
72
+ if (moveTargetLink == null)
73
+ {
74
+ // Add the destination for the NodeTarget (Owner)
75
+ moveTargetLink = InformationModel.MakeVariable<DynamicLink>("DynamicLink", FTOptix.Core.DataTypes.NodePath);
76
+ moveTargetLink.Value = "..@NodeId";
77
+ moveTargetLink.Mode = DynamicLinkMode.Read;
78
+ moveTarget.Refs.AddReference(FTOptix.CoreBase.ReferenceTypes.HasDynamicLink, moveTargetLink);
79
+ }
80
+ }
81
+ else
82
+ {
83
+ // Remove any existing dynamic link from the MoveTarget
84
+ if (moveTargetLink != null)
85
+ {
86
+ moveTarget?.Refs.RemoveReference(FTOptix.CoreBase.ReferenceTypes.HasDynamicLink, moveTargetLink.NodeId);
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### Custom UI types instances (widget instances)
93
+
94
+ When creating custom types or templates, the equivalent C# class is automatically created by FTOptix, then you can instantiate such classes with the same syntax
95
+
96
+ **Please note**: The user-defined types does not exists when running scripts at DesignTime, so they should be treated as normal objects (see the DesignTime snippet below)
97
+
98
+ #### RunTime creation of UI instances
99
+
100
+ ```csharp
101
+ // This syntax is only valid at Runtime, while designing the app,
102
+ // the CustomMotorWidget class does not exist
103
+ var myCustomPanel = InformationModel.Make<CustomMotorWidget>("MotorWidget");
104
+ // Add it to the page
105
+ Owner.Add(myCustomPanel);
106
+ ```
107
+
108
+ #### DesignTime creation of UI instances
109
+
110
+ ```csharp
111
+ // This method works both at Runtime and Design-time
112
+ // Get the original type to be instantiated
113
+ var myCustomPanelType = Project.Current.Get("path/to/type")
114
+ // Create an object by specifying the custom type
115
+ var myCustomPanel = InformationModel.MakeObject("MotorWidget", myCustomPanelType.NodeId);
116
+ // Add the new instance to the screen
117
+ Project.Current.Get("UI/Screens/Screen1").Add(myCustomPanel);
118
+ ```
119
+
120
+ ### Create a Polyline
121
+
122
+ ```csharp
123
+ /// <summary>
124
+ /// Create a PolyLine UI object and add it to the current owner.
125
+ /// </summary>
126
+ public void CreatePolyline()
127
+ {
128
+ var myLine = InformationModel.Make<PolyLine>("MyPolyline");
129
+ myLine.Width = 200;
130
+ myLine.Height = 0;
131
+ myLine.LeftMargin = 50;
132
+ myLine.TopMargin = 50;
133
+ myLine.LineThickness = 3;
134
+ myLine.FillColor = Colors.Black;
135
+ // SVG path describing the polyline
136
+ myLine.Path = "M 0.00000 0.00000 L 1.00000 1.00000";
137
+ Owner.Add(myLine);
138
+ }
139
+ ```
140
+
141
+ ### Open / Close all Accordion widgets from a starting node
142
+
143
+ ```csharp
144
+ /// <summary>
145
+ /// Recursively search from a starting node and open or close all Accordion widgets found.
146
+ /// Inputs: a NodeId of the starting node and a boolean `open` (true=open, false=close).
147
+ /// Caution: this method traverses the children tree and may be slow on large projects - run in a background task if needed.
148
+ /// </summary>
149
+ [ExportMethod]
150
+ public void ToggleAccordions(NodeId startingNode, bool open)
151
+ {
152
+ var root = InformationModel.Get(startingNode);
153
+ if (root == null)
154
+ {
155
+ Log.Error("ToggleAccordions", "Starting node not found");
156
+ return;
157
+ }
158
+ NavigateProjectNodes(root, open);
159
+ }
160
+
161
+ private void NavigateProjectNodes(IUANode obj, bool open)
162
+ {
163
+ foreach (var item in obj.Children)
164
+ {
165
+ switch (item.NodeClass)
166
+ {
167
+ case NodeClass.Object:
168
+ try
169
+ {
170
+ if (((UAManagedCore.UAObject)item).ObjectType.BrowseName == "Accordion")
171
+ {
172
+ var acc = (Accordion)item;
173
+ acc.Expanded = open;
174
+ }
175
+ }
176
+ catch (Exception ex)
177
+ {
178
+ Log.Warning("ToggleAccordions", "Skipped a node while traversing: " + ex.Message);
179
+ }
180
+ // Recurse into children
181
+ NavigateProjectNodes(item, open);
182
+ break;
183
+ case NodeClass.Variable:
184
+ // ignore variables
185
+ break;
186
+ default:
187
+ break;
188
+ }
189
+ }
190
+ }
191
+ ```
192
+
193
+
194
+ ## IUAObjects
195
+
196
+ Objects are generic containers that can hold variables or other OPC/UA objects and instances
197
+
198
+ ### Create a custom Object type
199
+
200
+ ```csharp
201
+ // Create a new Object Type
202
+ var newObject = InformationModel.MakeObjectType("NewMotorType");
203
+ // Add some properties to the Object type
204
+ newObject.Add(InformationModel.MakeVariable("Speed", OpcUa.DataTypes.Int32));
205
+ newObject.Add(InformationModel.MakeVariable("Power", OpcUa.DataTypes.Bool));
206
+ // Add the Object Type to the Model folder
207
+ Project.Current.Get("Model/Templates").Add(newObject);
208
+ ```
209
+
210
+ ### DesignTime creation of custom Object instances
211
+
212
+ After the custom type has been created, new instances can be created with a slightly different syntax
213
+
214
+ ```csharp
215
+ // Get the custom type definition
216
+ var customType = Project.Current.Get("Model/Templates/CustomMotor");
217
+ // Create the new object as instance of the custom type
218
+ var customTypeInstance = InformationModel.MakeObject("MotorInstance1", customType.NodeId);
219
+ // Add the new instance to the Model folder
220
+ Project.Current.Get("Model/instances").Add(customTypeInstance);
221
+ ```
222
+
223
+ ### RunTime creation of custom Object instances
224
+
225
+ ```csharp
226
+ // This syntax only works at Runtime,
227
+ // get the MotorType class and create a new object
228
+ var myObj = InformationModel.MakeObject<MotorType>("NewMotorInstance");
229
+ // Add the object to the parent element
230
+ Owner.Add(myObj);
231
+ ```
232
+
233
+ ## Custom behavior
234
+
235
+ OPC/UA objects can expose custom OPC/UA methods that can be called from any connected client.
236
+
237
+ How to add a custom behavior:
238
+
239
+ 1. Create an Object
240
+ 1. Add some children variables
241
+ 1. Convert the Object into Type
242
+ 1. Right click on the Object Type and click `Add Custom Behavior`
243
+ 1. Double click the Object Type and Visual Studio will appear
244
+
245
+ Now that the new class is created you can add as many C# methods as you need. Children variables can be accessed by calling `Node.[VariableName]`
246
+
247
+ ```csharp
248
+ [ExportMethod]
249
+ public void StartMotor() {
250
+ // Node refers to the current object ("this")
251
+ Node.Running = true;
252
+ Node.CurSpeed = Node.SetSpeed;
253
+ }
254
+
255
+ [ExportMethod]
256
+ public void StopMotor() {
257
+ Node.Running = false;
258
+ Node.CurSpeed = (Int32)0;
259
+ }
260
+
261
+ [ExportMethod]
262
+ Public void Banana(int a, int b, out int c) {
263
+ c = a + b;
264
+ }
265
+
266
+ #region Auto-generated code, do not edit!
267
+ protected new MotorWithBehaviorType Node => (MotorWithBehaviorType)base.Node;
268
+ #endregion
269
+ ```
270
+
271
+ ## Detect the Object Type of an element
272
+
273
+ ### Extract the BrowseName of the Type of any element
274
+
275
+ ```csharp
276
+ // Cast myVar to IUAVariable to read the DataType,
277
+ // then get it from the InformationModel and read the BrowseName
278
+ String dataType = InformationModel.Get(((IUAVariable)myVar).DataType).BrowseName;
279
+ ```
280
+
281
+ ```csharp
282
+ // Get the Variable to read the type
283
+ var dataSource = InformationModel.Get(Owner.GetVariable("Model").Value);
284
+ // Get it as a string
285
+ String baseType = dataSource.GetType().FullName.ToString()
286
+ ```
287
+
288
+ ### More advanced scenarios
289
+
290
+ This method expects the `BrowseName` of a `Screen` and makes a recursive search starting from a root node
291
+
292
+ ```csharp
293
+ private NodeId RecursiveSearch(IUANode inputObject, String screenType) {
294
+ // Browse all children of the starting node
295
+ foreach (IUANode childrenObject in inputObject.Children) {
296
+ try {
297
+ if (childrenObject is FTOptix.Core.Folder) {
298
+ // Start looking into the folder
299
+ Log.Verbose1("FindPages.Folder", "Found folder with name [" + childrenObject.BrowseName + "] and Type: [" + childrenObject.GetType().ToString() + "]");
300
+ // Recursive call to keep browsing
301
+ RecursiveSearch(childrenObject, screenType);
302
+ } else if (((UAManagedCore.UAObjectType)childrenObject).SuperType.BrowseName == screenType) {
303
+ // If the screen type was found, return it
304
+ return childrenObject.NodeId
305
+ } else {
306
+ // Other type that does not need to be used
307
+ Log.Verbose1("FindPages.Else", "Found unknown with name [" + childrenObject.BrowseName + "] and Type: [" + childrenObject.GetType().ToString() + "]");
308
+ }
309
+ } catch (Exception ex) {
310
+ // Handle exceptions
311
+ Log.Error("FindPages.Catch", "Exception thrown: " + ex.Message);
312
+ }
313
+ }
314
+ }
315
+
316
+ ```
317
+
318
+ ## Find types derived from a specific type
319
+
320
+ In the OPC/UA model, types can be derived from other types. This means that a type can inherit properties and methods from another type. To find all types derived from a specific type, you need to navigate through the references of the starting type type.
321
+
322
+ > [!NOTE]
323
+ > The routine might be called recursively, as derived types can have their own derived types, and so on. This is useful for exploring the hierarchy of types in the OPC/UA model.
324
+
325
+ ### Find all types derived from BaseEventType
326
+
327
+ ```csharp
328
+ public class FindBaseEventTypesRecursively : BaseNetLogic
329
+ {
330
+ [ExportMethod]
331
+ public void FindBaseEventTypeSubtypes()
332
+ {
333
+ recursiveTypesSearchTask = new LongRunningTask(RecursiveSearchMethod, LogicObject);
334
+ recursiveTypesSearchTask.Start();
335
+ }
336
+
337
+ private void RecursiveSearchMethod()
338
+ {
339
+ RecursiveSearch(null);
340
+ Log.Info($"Found {foundSubtypes.Count} subtypes of BaseEventType.");
341
+ recursiveTypesSearchTask.Dispose();
342
+ }
343
+
344
+ private void RecursiveSearch(IUANode baseEventType = null)
345
+ {
346
+ if (baseEventType == null)
347
+ {
348
+ baseEventType = InformationModel.Get(OpcUa.ObjectTypes.BaseEventType);
349
+ if (baseEventType == null)
350
+ {
351
+ Log.Error("BaseEventType not found in the information model.");
352
+ return;
353
+ }
354
+ }
355
+
356
+ var subtypes = baseEventType.Refs.GetNodes(OpcUa.ReferenceTypes.HasSubtype);
357
+
358
+ foreach (var subtype in subtypes)
359
+ {
360
+ Log.Info($"Found subtype: {subtype.BrowseName}");
361
+ foundSubtypes.Add(subtype);
362
+ RecursiveSearch(subtype);
363
+ }
364
+ }
365
+
366
+ private LongRunningTask recursiveTypesSearchTask;
367
+ private List<IUANode> foundSubtypes = new List<IUANode>();
368
+ }
369
+ ```
370
+