@aryacode/dsh-engineering 0.4.22 → 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 (76) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/README.md +10 -7
  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/ftview/SKILL.md +6 -0
  8. package/vendor/ftview/lib/model.d.ts +8 -3
  9. package/vendor/ftview/lib/model.js +63 -16
  10. package/vendor/l5x/lib/engine/analysis.d.ts +9 -1
  11. package/vendor/l5x/lib/engine/analysis.js +28 -3
  12. package/vendor/l5x/lib/engine/change-set.js +5 -4
  13. package/vendor/l5x/lib/engine/cip-request.d.ts +1 -0
  14. package/vendor/l5x/lib/engine/cip-request.js +71 -26
  15. package/vendor/l5x/lib/engine/direct-polling.js +12 -6
  16. package/vendor/l5x/lib/engine/review.js +12 -1
  17. package/vendor/l5x/lib/engine/studio-sdk.js +24 -6
  18. package/vendor/mwi/code/mw_code.py +4 -1
  19. package/vendor/mwi/legacy/native-variables.js +9 -1
  20. package/vendor/mwi/lib/read/service.d.ts +7 -1
  21. package/vendor/mwi/lib/read/service.js +13 -1
  22. package/vendor/mwi/lib/session/service.js +7 -1
  23. package/vendor/optix/SKILL.md +68 -0
  24. package/vendor/optix/netlogic/SOURCE.json +12 -0
  25. package/vendor/optix/netlogic/index.json +1987 -0
  26. package/vendor/optix/netlogic/pages/accessing-project-nodes.md +113 -0
  27. package/vendor/optix/netlogic/pages/advanced-svg.md +124 -0
  28. package/vendor/optix/netlogic/pages/alarming.md +489 -0
  29. package/vendor/optix/netlogic/pages/async-tasks.md +236 -0
  30. package/vendor/optix/netlogic/pages/audit-signature.md +91 -0
  31. package/vendor/optix/netlogic/pages/colors.md +122 -0
  32. package/vendor/optix/netlogic/pages/companion-specs.md +77 -0
  33. package/vendor/optix/netlogic/pages/creating-objects.md +370 -0
  34. package/vendor/optix/netlogic/pages/database-interaction.md +437 -0
  35. package/vendor/optix/netlogic/pages/datagrids.md +123 -0
  36. package/vendor/optix/netlogic/pages/debugging-tips.md +605 -0
  37. package/vendor/optix/netlogic/pages/designtime-tags-import.md +531 -0
  38. package/vendor/optix/netlogic/pages/dialog-boxes.md +150 -0
  39. package/vendor/optix/netlogic/pages/dispatch-events.md +200 -0
  40. package/vendor/optix/netlogic/pages/dynamic-links.md +825 -0
  41. package/vendor/optix/netlogic/pages/element-access.md +1208 -0
  42. package/vendor/optix/netlogic/pages/engineering-units.md +298 -0
  43. package/vendor/optix/netlogic/pages/events.md +340 -0
  44. package/vendor/optix/netlogic/pages/execute-command.md +202 -0
  45. package/vendor/optix/netlogic/pages/fto-studio-cli.md +99 -0
  46. package/vendor/optix/netlogic/pages/good-practices.md +50 -0
  47. package/vendor/optix/netlogic/pages/information-model.md +89 -0
  48. package/vendor/optix/netlogic/pages/log-output.md +22 -0
  49. package/vendor/optix/netlogic/pages/managing-aliases.md +22 -0
  50. package/vendor/optix/netlogic/pages/manipulate-nodes.md +72 -0
  51. package/vendor/optix/netlogic/pages/mqtt.md +240 -0
  52. package/vendor/optix/netlogic/pages/netlogic-lifecycle.md +270 -0
  53. package/vendor/optix/netlogic/pages/netlogic-overview.md +155 -0
  54. package/vendor/optix/netlogic/pages/opcua.md +325 -0
  55. package/vendor/optix/netlogic/pages/plc-tags.md +219 -0
  56. package/vendor/optix/netlogic/pages/queries.md +1297 -0
  57. package/vendor/optix/netlogic/pages/random-generation.md +90 -0
  58. package/vendor/optix/netlogic/pages/recipes.md +375 -0
  59. package/vendor/optix/netlogic/pages/recipex.md +2383 -0
  60. package/vendor/optix/netlogic/pages/regex.md +15 -0
  61. package/vendor/optix/netlogic/pages/register-observers.md +346 -0
  62. package/vendor/optix/netlogic/pages/reports.md +141 -0
  63. package/vendor/optix/netlogic/pages/resource-uri.md +308 -0
  64. package/vendor/optix/netlogic/pages/runtime-tags-import.md +280 -0
  65. package/vendor/optix/netlogic/pages/serial-port.md +357 -0
  66. package/vendor/optix/netlogic/pages/sessions.md +58 -0
  67. package/vendor/optix/netlogic/pages/system-node.md +153 -0
  68. package/vendor/optix/netlogic/pages/template-library.md +127 -0
  69. package/vendor/optix/netlogic/pages/threading.md +236 -0
  70. package/vendor/optix/netlogic/pages/translations.md +417 -0
  71. package/vendor/optix/netlogic/pages/trends.md +128 -0
  72. package/vendor/optix/netlogic/pages/ui-animations.md +115 -0
  73. package/vendor/optix/netlogic/pages/users-groups.md +416 -0
  74. package/vendor/optix/netlogic/pages/variables-formatting.md +16 -0
  75. package/vendor/optix/netlogic/pages/variables-interaction.md +557 -0
  76. package/vendor/optix/netlogic/pages/variables-structure.md +155 -0
@@ -0,0 +1,202 @@
1
+ # Calling or running commands
2
+
3
+ ## OPC/UA Methods
4
+
5
+ See [here](./creating-objects.md)
6
+
7
+ ## Run external commands (CMD or external softwares)
8
+
9
+ ```csharp
10
+ using System.Diagnostics;
11
+
12
+ static void RunCommand(string command)
13
+ {
14
+ int exitCode;
15
+ ProcessStartInfo processInfo;
16
+ Process process;
17
+ // Create the new command and launch it using the command prompt
18
+ processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
19
+ processInfo.CreateNoWindow = true;
20
+ processInfo.UseShellExecute = false;
21
+ //Redirect the output
22
+ processInfo.RedirectStandardError = true;
23
+ processInfo.RedirectStandardOutput = true;
24
+ // Start the process
25
+ process = Process.Start(processInfo);
26
+ process.WaitForExit();
27
+ // Read the streams
28
+ // Warning: This approach can lead to deadlocks
29
+ string output = process.StandardOutput.ReadToEnd();
30
+ string error = process.StandardError.ReadToEnd();
31
+ // Read the exit code
32
+ exitCode = process.ExitCode;
33
+ // Print some output
34
+ Log.Info("RunCommand", "output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
35
+ Log.Info("RunCommand", "error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
36
+ Log.Info("RunCommand", "ExitCode: " + exitCode.ToString());
37
+ // Close the process handler
38
+ process.Close();
39
+ }
40
+ ```
41
+
42
+ ## Open a WebBrowser to a specific page
43
+
44
+ ```csharp
45
+ [ExportMethod]
46
+ public void OpenBrowser(string urlPath) {
47
+ //string destinationPath = new ResourceUri(urlPath).Uri;
48
+ string destinationPath = urlPath;
49
+ Process myProcess = new Process();
50
+
51
+ try {
52
+ // true is the default, but it is important not to set it to false
53
+ myProcess.StartInfo.UseShellExecute = true;
54
+ myProcess.StartInfo.FileName = destinationPath;
55
+ // Start the process
56
+ myProcess.Start();
57
+ } catch (Exception e) {
58
+ // Print any exception (if needed)
59
+ Log.Error("OpenInBrowser", e.Message);
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Invoke FT Optix Core commands
65
+
66
+ > [!NOTE]
67
+ > Core commands can only be invoked at runtime.
68
+
69
+ ```csharp
70
+ // Get the core commands object (exposed by FactoryTalk Optix APIs)
71
+ var coreCommandsObject = InformationModel.GetObject(FTOptix.CoreBase.Objects.CoreCommands);
72
+ // Call a specific command
73
+ coreCommandsObject.ExecuteMethod("Close");
74
+ ```
75
+
76
+ ## Invoke FactoryTalk Optix Alarm commands
77
+
78
+ > [!NOTE]
79
+ > Alarm commands can only be invoked at runtime.
80
+
81
+ ```csharp
82
+ // Get the alarms object
83
+ var alarmCommands = InformationModel.GetObject(FTOptix.Alarm.Objects.AlarmCommands);
84
+ // Acknowledge all alarms
85
+ alarmCommands.ExecuteMethod("AcknowledgeAll");
86
+ // Confirm all alarms
87
+ alarmCommands.ExecuteMethod("ConfirmAll");
88
+ ```
89
+
90
+ ## Perform system shutdown (Windows only)
91
+
92
+ ```csharp
93
+ /// <summary>
94
+ /// Trigger a Windows shutdown using the system 'shutdown' command.
95
+ /// Use with caution; this will stop the entire machine.
96
+ /// </summary>
97
+ [ExportMethod]
98
+ public void SystemShutDown()
99
+ {
100
+ var psi = new ProcessStartInfo("shutdown", "/s /t 0");
101
+ psi.CreateNoWindow = true;
102
+ psi.UseShellExecute = false;
103
+ Process.Start(psi);
104
+ }
105
+ ```
106
+
107
+ ## Run a .BAT or external executable
108
+
109
+ ```csharp
110
+ /// <summary>
111
+ /// Start a BAT file or external program. Adjust filename and parameters as needed.
112
+ /// On Windows, you can call cmd with /k or /c; /k keeps the window open.
113
+ /// </summary>
114
+ private void ExecuteExternalCommand()
115
+ {
116
+ var Test = new Process();
117
+ string filename = @"C:\Path\To\Script.bat";
118
+ string parameters = $"/k \"{filename}\"";
119
+ Process.Start("cmd", parameters);
120
+ }
121
+ ```
122
+
123
+ ```csharp
124
+ // Example: launch VLC with parameters
125
+ [ExportMethod]
126
+ public void OpenVLC()
127
+ {
128
+ Process VLC = new Process();
129
+ VLC.StartInfo.FileName = @"C:\Program Files (x86)\VideoLAN\VLC\vlc.exe";
130
+ VLC.StartInfo.Arguments = " --fullscreen --play-and-exit C:\\path\\to\\video.mp4";
131
+ VLC.Start();
132
+ }
133
+ ```
134
+
135
+ ## Invoke a method from a different NetLogic
136
+
137
+ Calling a NetLogic instance with `var myNetLogic = new MyNetLogic();` will create a new instance of the NetLogic, but it will not be the same as the one that is running in the project so it should be avoided. To call a method from a different NetLogic, you need to get the NetLogic object from the project and then call the method on that object.
138
+
139
+ > [!NOTE]
140
+ > Methods from other NetLogic instances can only be invoked at runtime.
141
+
142
+ ```csharp
143
+ [ExportMethod]
144
+ public void CallMethod1()
145
+ {
146
+ // Get the NetLogic containing the method to invoke
147
+ var myScript = Project.Current.GetObject("NetLogic/RuntimeNetLogic1");
148
+ // Launch the method
149
+ myScript.ExecuteMethod("Method1");
150
+ }
151
+ ```
152
+
153
+ ### Invoke a method from a different NetLogic with parameters
154
+
155
+ #### NetLogic to be called
156
+
157
+ ```csharp
158
+ public class AlarmGridLogic : BaseNetLogic
159
+ {
160
+ [ExportMethod]
161
+ public void AckAllAlarmsWithMessage(object[] arguments)
162
+ {
163
+ var ackMessage = (LocalizedText) arguments[0];
164
+ var alarmsList = GetAllAlarms();
165
+ if (alarmsList.Count == 0)
166
+ {
167
+ Log.Warning("No alarms to acknowledge");
168
+ return;
169
+ }
170
+ ProcessAlarms(ackMessage, alarmsList, (alarm, message) => alarm.Acknowledge(message));
171
+ }
172
+ }
173
+ ```
174
+
175
+ #### Caller
176
+
177
+ ```csharp
178
+ public class AckConfirmMessageLogic : BaseNetLogic
179
+ {
180
+ [ExportMethod]
181
+ public void PerformAction()
182
+ {
183
+ // Get the target NetLogic object
184
+ var alarmsNetLogic = GetNetLogicObject();
185
+ // Get the action name to be invoked
186
+ string action = Owner.GetVariable("MethodName").Value;
187
+ // Get the comment to be added to the alarm
188
+ var comment = Owner.Get<TextBox>("Comment").LocalizedText;
189
+ // Create the object arguments to be passed to the method
190
+ object[] arguments = new object[] { comment };
191
+ alarmsNetLogic.ExecuteMethod(action, [arguments]);
192
+ (Owner as Dialog)?.Close();
193
+ }
194
+
195
+ private IUAObject GetNetLogicObject()
196
+ {
197
+ // Here the NetLogic is passed as a variable to the owner object,
198
+ // but it could be retrieved in a different way (like Project.Current.GetObject)
199
+ return InformationModel.GetObject(Owner.GetVariable("AlarmGridLogic").Value);
200
+ }
201
+ }
202
+ ```
@@ -0,0 +1,99 @@
1
+ # FactoryTalk Optix Studio CLI
2
+
3
+ ## Export an application to be loaded in an Optix Panel via USB
4
+
5
+ This script leverages the FactoryTalk Optix Studio CLI to export an application and prepare it to be imported in an Optix Panel via USB.
6
+
7
+ > [!TIP]
8
+ > The `LoadApplicationWidget` should be used to load the application in the Optix Panel, this script only prepares the ZIP file with the correct structure and encryption.
9
+
10
+ ```powershell
11
+ $projectPath = "D:\temp\NewHMIProject12\NewHMIProject12.optix"
12
+ $optixIdePath = "C:\Program Files\Rockwell Automation\FactoryTalk Optix\Studio 1.6.2.36\FTOptixStudio.exe"
13
+ $7zipPath = "C:\Program Files\7-Zip\7z.exe"
14
+ $outputPath = "C:\Users\LabUser\Downloads\"
15
+ $platform = "Yocto_arm64"
16
+ $optixPanelPassword = "YourOptixPanelAdminPassword"
17
+
18
+ # Create a temporary directory for the export process
19
+ Write-Host "Creating temporary directory for export..."
20
+ $tempDir = New-Item -ItemType Directory -Path "$env:TEMP\OptixExportTemp" -Force
21
+ Write-Host "Temporary directory created at $tempDir"
22
+
23
+ # Export the project using Optix IDE
24
+ Write-Host "Exporting project using Optix IDE..."
25
+ Start-Process -FilePath "$optixIdePath" -ArgumentList "export `"$projectPath`" --platform=`"$platform`" --location=`"$tempDir`"" -Wait
26
+
27
+ # Update the .optix file with the EncryptionMode
28
+ Write-Host "Updating .optix file with EncryptionMode..."
29
+ $optixFilePath = Get-ChildItem -Path $tempDir -Recurse -Filter "*.optix" | Select-Object -First 1
30
+ if ($null -eq $optixFilePath) {
31
+ Write-Error "No .optix file found in the exported directory."
32
+ Write-Host "Searching for all files in temp directory for debugging:"
33
+ Get-ChildItem -Path $tempDir -Recurse | ForEach-Object { Write-Host $_.FullName }
34
+ exit 1
35
+ }
36
+ Write-Host "Found .optix file at: $($optixFilePath.FullName)"
37
+
38
+ # Extract the CoreVersion from the .optix YAML file and add encryption settings
39
+ $optixFileContent = Get-Content -Path $optixFilePath.FullName
40
+ $coreVersionLine = $optixFileContent | Where-Object { $_ -match "CoreVersion:" }
41
+ if ($null -eq $coreVersionLine) {
42
+ Write-Error "CoreVersion not found in the .optix file."
43
+ exit 1
44
+ }
45
+
46
+ $coreVersion = $coreVersionLine -replace "CoreVersion:\s*", ""
47
+ Write-Host "CoreVersion found: $coreVersion"
48
+
49
+ # Add encryption settings after CoreVersion line
50
+ $updatedContent = @()
51
+ foreach ($line in $optixFileContent) {
52
+ $updatedContent += $line
53
+ if ($line -match "CoreVersion:") {
54
+ $updatedContent += " EncryptionVersion: 1"
55
+ $updatedContent += " EncryptionMode: YAMLFiles"
56
+ Write-Host "Added encryption settings after CoreVersion: $coreVersion"
57
+ }
58
+ }
59
+
60
+ # Write the updated content back to the .optix file
61
+ $updatedContent | Set-Content -Path $optixFilePath.FullName
62
+
63
+ # Write the content of the XML file
64
+ Write-Host "Creating DeviceConfiguration.xml..."
65
+ $xmlFilePath = Join-Path -Path $tempDir -ChildPath "DeviceConfiguration.xml"
66
+ $xmlContent = "<?xml version=""1.0"" encoding=""utf-8""?>
67
+ <DeviceConfiguration>
68
+ <Actions>
69
+ <ImportFTOptixApplication EncryptProject=""true""/>
70
+ </Actions>
71
+ </DeviceConfiguration>"
72
+
73
+ try {
74
+ $xmlContent | Out-File -FilePath $xmlFilePath -Encoding Ascii
75
+ Write-Host "DeviceConfiguration.xml created successfully at: $xmlFilePath"
76
+ } catch {
77
+ Write-Error "Failed to create XML file: $($_.Exception.Message)"
78
+ exit 1
79
+ }
80
+
81
+ # Create a zip archive of the exported project
82
+ Write-Host "Creating ZIP archive..."
83
+ $outputZipPath = Join-Path -Path $outputPath -ChildPath "FTOptixApplication.z"
84
+
85
+ # Compress it to ZIP file with Fast method and AES-256 encryption
86
+ Write-Host "Compressing to ZIP with AES-256 encryption..."
87
+ & "$7zipPath" a -tzip -mx=3 "-p$optixPanelPassword" "$outputZipPath" "$tempDir\*"
88
+
89
+ # Check if the compression was successful
90
+ if ($LASTEXITCODE -ne 0) {
91
+ Write-Error "Failed to create ZIP archive."
92
+ exit 1
93
+ }
94
+
95
+ # Clean up the temporary directory
96
+ Remove-Item -Path $tempDir -Recurse -Force
97
+
98
+ Write-Host "Export completed. The ZIP file is located at $outputZipPath"
99
+ ```
@@ -0,0 +1,50 @@
1
+ # Good practices
2
+
3
+ Here is a list of convention our FactoryTalk Optix technicians uses when creating new projects, feel free to choose if this can apply to your project
4
+
5
+ - Use significative names for every project element (no default names)
6
+ - Exception is made when creating object types, still remember to give meaningful name if possible
7
+ - Avoid using number at the end of item name
8
+ - Avoid abbreviations in object names to improve readability
9
+ - Examples:
10
+ - `Templates/SpinBox (Type)` -> BAD
11
+ - `Templates/SpinBoxWithGreenBorder (Type)` -> GOOD
12
+ - `MainWindow/SpinBox1` -> BAD
13
+ - `MainWindow/MotorSpeed_SpinBox` -> GOOD
14
+ - `MainWindow/MotorSP_SB` -> BAD
15
+ - Nice to use same EmbeddedDatabase for every item to be stored
16
+ - Multiple tables can be used in same EmbeddedDatabase with different settings (RecordLimit, Names, etc)
17
+ - Use `PascalCase` for object names
18
+ - Use `camelCase` for variable names (Model, Session and Local variables)
19
+ - All graphical elements should be in `UI` folder
20
+ - Here you can create standard folders to organize your work, such as:
21
+ - `UI/Templates`-> Contains all custom types used to create objects
22
+ - `UI/Screens` -> Contains the different pages that are used in the project
23
+ - Both subfolder can have children subfolder to organize elements if needed
24
+ - Example:
25
+ - `UI/Templates/MotorWidgets`
26
+ - `UI/Templates/PumpsWidgets`
27
+ - `UI/Screens/Filler`
28
+ - `UI/Screens/Settings`
29
+ - Nice to use Templates folder in any first level project folder (e.g. UI, Model, Converters, etc...) when creating custom types
30
+
31
+ - Global variables should be created in the `Model` folder (and subfolder)
32
+ - Nice to use HTML color palette if no special need for custom coloring
33
+ - Example:
34
+ - `red` -> GOOD
35
+ - `#FFA1C8` -> BAD
36
+ - Object names and LocalizationDictionary keys should be in English
37
+ - Nice to sort items by their type in project tree
38
+ - Exception is made when defining layers is necessary to build final interface (bottom most element is highest layer)
39
+ - When creating a new page/container, avoid using a `Panel` with a `Rectangle` as coloured background to avoid doubling project nodes
40
+ - Use instead:
41
+ - `Screen` if the object is a whole screen that is going to be displayed in the HMI
42
+ - `Rectangle` if coloured background is needed
43
+ - `Panel` if background should be transparent (usually to group elements)
44
+ - Nice to group items using Panel
45
+ - This is useful to reduce project complexity when assigning groups-based permissions and/or to trigger specific visual logics (enabling, visibility, etc)
46
+ - Nice to use same `Label` name and `LocalizationDictionary` item key
47
+ - Nice to use keyword in controls names to identify which variable/object is referring to
48
+ - Example:
49
+ - `VoltageText` -> Label that shows the translation key for the _Voltage_ element
50
+ - `VoltageValue` -> Name for a LinearGauge controlling _Voltage_ value
@@ -0,0 +1,89 @@
1
+ # The Information Model
2
+
3
+ ## Overview
4
+
5
+ In FactoryTalk Optix, each and every object is a `node`, the definition of a node comes from the OPC/UA specifications which states that an OPC/UA node is like an entity representing information. Some Nodes are Variables, DataType, References, Object, Methods... depending of what they are used for.
6
+
7
+ The OPC/UA specifications can be found at the following link [opcfoundation resources](https://opcfoundation.org/developer-tools/documents/?type=Specification) and search for [OPC 10000-1 UA Part 1: Overview and Concepts](https://opcfoundation.org/developer-tools/documents/view/158) and [OPC 10000-3 UA Part 3: Address Space Model](https://opcfoundation.org/developer-tools/documents/view/160)
8
+
9
+ Understanding the concept of nodes is crucial when working with FactoryTalk Optix because it forms the backbone of the OPC/UA information model, which FactoryTalk Optix leverages for data representation and interaction. Nodes represent various types of information and their relationships, enabling a standardized way to access and manipulate data within the system. This allows integration and interoperability between different components and devices, ensuring that data can be efficiently managed and utilized across the entire project.
10
+
11
+ ### The Information Model of OPC/UA
12
+
13
+ The OPC Unified Architecture (OPC/UA) defines a rich information model that allows for complex data representation and interaction. At the core of this model is the concept of a "node". A node is an entity that represents information and can be of various types, each serving a different purpose within the information model. The major properties of a node include:
14
+
15
+ - **NodeId**: A unique identifier for the node within the address space.
16
+ - **BrowseName**: A human-readable name used for browsing the node.
17
+ - **DisplayName**: A localized name intended for display purposes.
18
+ - **Description**: A localized text description of the node.
19
+
20
+ Nodes can be of different types, including:
21
+
22
+ - **Object**: Represents physical or abstract entities.
23
+ - **Variable**: Holds a value and can have a data type.
24
+ - **Method**: Represents callable functions or procedures.
25
+ - **ObjectType**: Defines the type of an object.
26
+ - **VariableType**: Defines the type of a variable.
27
+ - **ReferenceType**: Defines the type of a reference between nodes.
28
+ - **DataType**: Defines the data type of a variable.
29
+ - **View**: Represents a subset of the address space for browsing.
30
+
31
+ These nodes and their properties form the foundation of the OPC/UA information model, enabling a standardized way to represent and interact with data across different systems and devices.
32
+
33
+ ### The Information Model of FactoryTalk Optix
34
+
35
+ As everything in FactoryTalk Optix is actually an OPC/UA node, we can implement some complex scenarios like:
36
+
37
+ - Allowing other applications (both FactoryTalk Optix or third-parties) to read and write project nodes
38
+ - This includes exposing project elements like Databases, PLC Tags, Model variables, UI objects, etc
39
+ - Allowing other applications to produce and consume alarms and events using the OPC/UA A&E protocol
40
+ - Manipulating parts of the project using NetLogic or an external OPC/UA client
41
+
42
+ ## Project context
43
+
44
+ Accessing the path of the node will return the project-level node, this is good for global elements (Model Variables, PLC Tags, etc) but it cannot be used to access session-based elements, as each user session will have a unique instance of windows and pages with uniques NodeIds
45
+
46
+ ### Overview
47
+
48
+ ![Project vs session](../images/session-concept.png)
49
+
50
+ FactoryTalk Optix graphical interface is based on the object's oriented paradigm, this means that when defining UI elements at design-time, these are actually created as object types. When the runtime starts, and a session is created (NativePresentationEngine creates automatically one UI instance, each client of the WebPresentationEngine creates one UI instance), this session is derived from the UI type that was designed, thus becoming an instance.
51
+
52
+ Each session lives as an independent object, each session can interact with global objects (such as Model variables or PLC tags) but cannot access other sessions, when calling methods that targets a session object (such as the refresh of a DataGrid), it can only affect the session where the method was called, other instances and sessions are unaffected.
53
+
54
+ NetLogic are also affected by this functionality:
55
+ - When using the `Project.Current.Get` syntax, only the project definition can be accessed, if a UI element is manipulated using such syntax, the session instance must be destroyed and recreated in order to inherit the new changes (for example navigating to a different page and then coming back)
56
+ - When placing the NetLogic inside a page (which can be something like a Screen, a Panel, a Rectangle, or any UI object) and using the `Owner.Get` syntax, the specific instance where the NetLogic is created gets accessed and the UI is immediately refreshed. Only the instance where the NetLogic exists can be accessed, a session-based NetLogic cannot interact with other sessions, only with elements in the current session or global objects (such as PLC tags or Model variables).
57
+
58
+ ### Summary
59
+
60
+ - Each session of a PresentationEngine creates an instance of the UI types
61
+ - Each session is completely independent from other session
62
+ - A session can only interact with:
63
+ - Elements in the same session
64
+ - Global objects (Model variables, PLC tags, alarms, etc)
65
+ - A session cannot interact with other sessions
66
+ - Session changes are discarded when the instance is destroyed (page is changed or reloaded)
67
+ - Retentivity cannot be applied to session objects
68
+ - Retentivity should never be applied to any UI object
69
+ - A session can access global objects, but global objects cannot access session objects, for example:
70
+ - A global NetLogic cannot refresh the DataGrid of a session, a global NetLogic can only access nodes at the project level (such as alarms, PLC tags, Model variables, etc)
71
+ - A session NetLogic can access all global objects, all elements of the current UI session but cannot access other sessions.
72
+
73
+ ### Examples
74
+
75
+ #### Refreshing a DataGrid
76
+
77
+ As the DataGrid is a session object, the NetLogic to refresh a DataGrid must be placed at a session level
78
+
79
+ #### Creating a new alarm
80
+
81
+ As the Alarm is a global object, the NetLogic can be either at the session level or at a global level
82
+
83
+ #### Performing an SQL query
84
+
85
+ Here it depends on the final goal:
86
+
87
+ - If just inserting data to a database, the NetLogic can be either at the session level or at a global level, the data can be passed as global variable or as argument of the called method
88
+ - If performing a query (such as a SELECT) depending on some parameters from the user, the NetLogic must be placed at the session level (where TextBox or other controls can be accessed)
89
+ - If performing a query (such as a SELECT or an INSERT) depending on some values from the controller (PLC), the NetLogic can be placed either at a global or session level
@@ -0,0 +1,22 @@
1
+ # Log messages
2
+
3
+ Log messages can be displayed both at RunTime and DesignTime, at DesignTime logs will appear in `Optix Studio Output` while at RunTime they will appear in the `Emulator output` or the RunTime log
4
+
5
+ ## General syntax
6
+
7
+ `Log . [level] ( [optional category] , [ message content] );`
8
+
9
+ ## Examples
10
+
11
+ Different log levels can be triggered and then filtered in `Optix Studio Output` and `Emulator output`. Specifying an optional custom `Category` helps you understanding where this line was generated (for example the NetLogic name and/or the method name)
12
+
13
+ - `Log.Error(category, message);`
14
+ - `Log.Warning(category, message);`
15
+ - `Log.Info(category, message);`
16
+ - `Log.Debug(category, message);`
17
+ - `Log.Verbose1(category, message);`
18
+ - `Log.Verbose2(category, message);`
19
+
20
+ ## Get the node path for any project node
21
+
22
+ - `Log.Node(IUANode);` -> Returns a string containing the node path for a specific element
@@ -0,0 +1,22 @@
1
+ # Managing Aliases
2
+
3
+ ## Delete the value from an Alias
4
+
5
+ ```csharp
6
+ Project.Current.Get("UI/Pages/MainPage").SetAlias("MainBoilerAlias", NodeId.Empty);
7
+ ```
8
+
9
+ ## Delete the Kind property of an Alias
10
+
11
+ ```csharp
12
+ Project.Current.Get<Alias>("UI/Pages/MainPage/MainBoilerAlias").Kind = NodeId.Empty;
13
+ ```
14
+
15
+ ## Connect an Alias to a node
16
+
17
+ ```csharp
18
+ // Get the target variable
19
+ var targetVariable = Project.Current.Get<Tag>("CommDriver/RAEthernetIP/Station1/InletPump");
20
+ // Set the alias to the target value
21
+ Project.Current.Get("UI/Pages/MainPage").SetAlias("MainBoilerAlias", targetVariable.NodeId);
22
+ ```
@@ -0,0 +1,72 @@
1
+ # Manipulate Optix nodes
2
+
3
+ > [!WARNING]
4
+ > This page describes low-level features and should be used with caution as they can potentially lead to unexpected results or even break your project.
5
+ > These features are not officially supported and may be subject to changes in future releases.
6
+
7
+ > [!NOTE]
8
+ > Nodes behavior can only be manipulated at runtime.
9
+
10
+ ## Stopping an Optix node
11
+
12
+ Once nodes are stopped, they stop interacting with the system for example an ODBC database node will stop processing queries, a Trend node will stop logging data, an Alarm node will stop monitoring conditions, etc.
13
+
14
+ This can be useful in some scenarios to disable some components (like the `Signing Workflow` node) or to temporarily stop some processes (like a `Trend` node) without deleting them.
15
+
16
+ ```csharp
17
+ /// <summary>
18
+ /// Stops an Optix node if it is started
19
+ /// </summary>
20
+ /// <param name="node">The node to be stopped</param>
21
+ private void StopNode(IUANode node)
22
+ {
23
+ // Only objects can be started/stopped
24
+ if (node is IUAObject nodeObject && node.Status == NodeStatus.Started)
25
+ {
26
+ // Stop the node
27
+ nodeObject.Stop();
28
+ }
29
+
30
+ }
31
+ ```
32
+
33
+ ## Starting an Optix node
34
+
35
+ ```csharp
36
+ /// <summary>
37
+ /// Starts an Optix node if it is stopped
38
+ /// </summary>
39
+ /// <param name="node">The node to be started</param>
40
+ private void StartNode(IUANode node)
41
+ {
42
+ // Only objects can be started/stopped
43
+ if (node is IUAObject nodeObject && node.Status != NodeStatus.Started)
44
+ {
45
+ // Start the node
46
+ nodeObject.Start();
47
+ }
48
+
49
+ }
50
+ ```
51
+
52
+ ## Restarting an Optix node
53
+
54
+ This is simply a combination of the previous two methods
55
+
56
+ ```csharp
57
+ /// <summary>
58
+ /// Restarts an Optix node if it is started
59
+ /// </summary>
60
+ /// <param name="node">The node to be restarted</param>
61
+ private void RestartNode(IUANode node)
62
+ {
63
+ // Only objects can be started/stopped
64
+ if (node is IUAObject nodeObject && node.Status == NodeStatus.Started)
65
+ {
66
+ // Restart the node
67
+ nodeObject.Stop();
68
+ nodeObject.Start();
69
+ }
70
+
71
+ }
72
+ ```