@aryacode/dsh-engineering 0.5.0 → 0.7.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.
- package/CHANGELOG.md +52 -0
- package/README.md +9 -8
- package/cordis.patch.yml +1 -1
- package/entries/netlogic.js +266 -0
- package/entries/optix.js +13 -0
- package/package.json +10 -10
- package/vendor/l5x/SKILL.md +27 -7
- package/vendor/l5x/lib/engine/change-set.d.ts +9 -1
- package/vendor/l5x/lib/engine/change-set.js +32 -7
- package/vendor/l5x/lib/engine/documentation.d.ts +58 -0
- package/vendor/l5x/lib/engine/documentation.js +237 -0
- package/vendor/l5x/lib/engine/instructions.d.ts +50 -0
- package/vendor/l5x/lib/engine/instructions.js +107 -0
- package/vendor/l5x/lib/engine/ladder.d.ts +74 -0
- package/vendor/l5x/lib/engine/ladder.js +209 -0
- package/vendor/l5x/lib/index.d.ts +1 -0
- package/vendor/l5x/lib/index.js +3 -1
- package/vendor/l5x/lib/model/routines.js +6 -1
- package/vendor/l5x/lib/session.d.ts +20 -0
- package/vendor/l5x/lib/session.js +36 -0
- package/vendor/l5x/lib/tools/document.d.ts +18 -0
- package/vendor/l5x/lib/tools/document.js +119 -0
- package/vendor/l5x/lib/tools/drafts.js +109 -3
- package/vendor/optix/SKILL.md +68 -0
- package/vendor/optix/netlogic/SOURCE.json +12 -0
- package/vendor/optix/netlogic/index.json +1987 -0
- package/vendor/optix/netlogic/pages/accessing-project-nodes.md +113 -0
- package/vendor/optix/netlogic/pages/advanced-svg.md +124 -0
- package/vendor/optix/netlogic/pages/alarming.md +489 -0
- package/vendor/optix/netlogic/pages/async-tasks.md +236 -0
- package/vendor/optix/netlogic/pages/audit-signature.md +91 -0
- package/vendor/optix/netlogic/pages/colors.md +122 -0
- package/vendor/optix/netlogic/pages/companion-specs.md +77 -0
- package/vendor/optix/netlogic/pages/creating-objects.md +370 -0
- package/vendor/optix/netlogic/pages/database-interaction.md +437 -0
- package/vendor/optix/netlogic/pages/datagrids.md +123 -0
- package/vendor/optix/netlogic/pages/debugging-tips.md +605 -0
- package/vendor/optix/netlogic/pages/designtime-tags-import.md +531 -0
- package/vendor/optix/netlogic/pages/dialog-boxes.md +150 -0
- package/vendor/optix/netlogic/pages/dispatch-events.md +200 -0
- package/vendor/optix/netlogic/pages/dynamic-links.md +825 -0
- package/vendor/optix/netlogic/pages/element-access.md +1208 -0
- package/vendor/optix/netlogic/pages/engineering-units.md +298 -0
- package/vendor/optix/netlogic/pages/events.md +340 -0
- package/vendor/optix/netlogic/pages/execute-command.md +202 -0
- package/vendor/optix/netlogic/pages/fto-studio-cli.md +99 -0
- package/vendor/optix/netlogic/pages/good-practices.md +50 -0
- package/vendor/optix/netlogic/pages/information-model.md +89 -0
- package/vendor/optix/netlogic/pages/log-output.md +22 -0
- package/vendor/optix/netlogic/pages/managing-aliases.md +22 -0
- package/vendor/optix/netlogic/pages/manipulate-nodes.md +72 -0
- package/vendor/optix/netlogic/pages/mqtt.md +240 -0
- package/vendor/optix/netlogic/pages/netlogic-lifecycle.md +270 -0
- package/vendor/optix/netlogic/pages/netlogic-overview.md +155 -0
- package/vendor/optix/netlogic/pages/opcua.md +325 -0
- package/vendor/optix/netlogic/pages/plc-tags.md +219 -0
- package/vendor/optix/netlogic/pages/queries.md +1297 -0
- package/vendor/optix/netlogic/pages/random-generation.md +90 -0
- package/vendor/optix/netlogic/pages/recipes.md +375 -0
- package/vendor/optix/netlogic/pages/recipex.md +2383 -0
- package/vendor/optix/netlogic/pages/regex.md +15 -0
- package/vendor/optix/netlogic/pages/register-observers.md +346 -0
- package/vendor/optix/netlogic/pages/reports.md +141 -0
- package/vendor/optix/netlogic/pages/resource-uri.md +308 -0
- package/vendor/optix/netlogic/pages/runtime-tags-import.md +280 -0
- package/vendor/optix/netlogic/pages/serial-port.md +357 -0
- package/vendor/optix/netlogic/pages/sessions.md +58 -0
- package/vendor/optix/netlogic/pages/system-node.md +153 -0
- package/vendor/optix/netlogic/pages/template-library.md +127 -0
- package/vendor/optix/netlogic/pages/threading.md +236 -0
- package/vendor/optix/netlogic/pages/translations.md +417 -0
- package/vendor/optix/netlogic/pages/trends.md +128 -0
- package/vendor/optix/netlogic/pages/ui-animations.md +115 -0
- package/vendor/optix/netlogic/pages/users-groups.md +416 -0
- package/vendor/optix/netlogic/pages/variables-formatting.md +16 -0
- package/vendor/optix/netlogic/pages/variables-interaction.md +557 -0
- package/vendor/optix/netlogic/pages/variables-structure.md +155 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Random generation
|
|
2
|
+
|
|
3
|
+
When using the random generation, if the loop is particularly fast the system tick may not be different and the same number is generated twice, a small delay may help
|
|
4
|
+
|
|
5
|
+
## Random number generator
|
|
6
|
+
|
|
7
|
+
```csharp
|
|
8
|
+
Random r = new Random();
|
|
9
|
+
|
|
10
|
+
public void Start()
|
|
11
|
+
{
|
|
12
|
+
// Create a random integer value
|
|
13
|
+
Int variableRandom = r.Next(min, max);
|
|
14
|
+
// Create a random double value
|
|
15
|
+
Double variableRandom = r.NextDouble()
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Random strings generator
|
|
20
|
+
|
|
21
|
+
### Using custom character list
|
|
22
|
+
|
|
23
|
+
```csharp
|
|
24
|
+
private static Random random = new Random();
|
|
25
|
+
|
|
26
|
+
public static string RandomString(int stringLength)
|
|
27
|
+
{
|
|
28
|
+
// Set the subset of characters to be used
|
|
29
|
+
const string usableCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
30
|
+
// Return the random string
|
|
31
|
+
return new string(Enumerable.Repeat(usableCharacters, stringLength)
|
|
32
|
+
.Select(s => s[random.Next(s.Length)]).ToArray());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public void Start()
|
|
36
|
+
{
|
|
37
|
+
// Call the method to generate the string
|
|
38
|
+
String randomString = RandomString(10);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Using random GUID
|
|
43
|
+
|
|
44
|
+
Please note, this should **never** be used to generate passwords or tokens as it's not random enough. If high security is required, use the [RandomNumberGenerator](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator?view=net-8.0) instead.
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
private string RandomString()
|
|
48
|
+
{
|
|
49
|
+
// Create a new guid
|
|
50
|
+
Guid newGuid = Guid.NewGuid();
|
|
51
|
+
// Remove dashes to keep only alphanumeric characters
|
|
52
|
+
return newGuid.ToString().Replace("-", "");
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```csharp
|
|
57
|
+
private static string GenerateRandomString(int length = 8)
|
|
58
|
+
{
|
|
59
|
+
const string alphanumericChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
60
|
+
|
|
61
|
+
using var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
|
|
62
|
+
var bytes = new byte[length];
|
|
63
|
+
rng.GetBytes(bytes);
|
|
64
|
+
|
|
65
|
+
var chars = new char[length];
|
|
66
|
+
for (int i = 0; i < length; i++)
|
|
67
|
+
{
|
|
68
|
+
chars[i] = alphanumericChars[bytes[i] % alphanumericChars.Length];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return new string(chars);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This one should be better
|
|
76
|
+
|
|
77
|
+
```csharp
|
|
78
|
+
[ExportMethod]
|
|
79
|
+
public static void GenerateRandomString(out string randomString)
|
|
80
|
+
{
|
|
81
|
+
// Create a random string generator using the RandomNumberGenerator class
|
|
82
|
+
using var rng = RandomNumberGenerator.Create();
|
|
83
|
+
// Create a byte array to store the random values
|
|
84
|
+
var randomBytes = new byte[32];
|
|
85
|
+
// Fill the byte array with random values
|
|
86
|
+
rng.GetBytes(randomBytes);
|
|
87
|
+
// Convert the byte array to a string
|
|
88
|
+
randomString = Convert.ToBase64String(randomBytes).Substring(0, 32);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# Recipes
|
|
2
|
+
|
|
3
|
+
Recipes in FactoryTalk Optix provide a structured way to store and manage sets of parameters that can be loaded into your application. They are particularly useful for manufacturing processes where different product variants require different machine settings.
|
|
4
|
+
|
|
5
|
+
> [!WARNING]
|
|
6
|
+
> This section is a work in progress and might be updated with more examples and explanations in the future.
|
|
7
|
+
> Please report any issues or suggestions to the FactoryTalk Optix support or community forums.
|
|
8
|
+
|
|
9
|
+
> [!NOTE]
|
|
10
|
+
> The legacy recipes engine in FactoryTalk Optix allows a maximum of 2048 ingredients per recipe. This limit is imposed by the underlying database system and cannot be changed.
|
|
11
|
+
|
|
12
|
+
> [!NOTE]
|
|
13
|
+
> The content of this page can only be applied to the legacy recipe module of FactoryTalk Optix. The reference guide for the new recipe module can be accessed [here](./recipex.md).
|
|
14
|
+
|
|
15
|
+
## Recipe System Overview
|
|
16
|
+
|
|
17
|
+
The recipe system in FactoryTalk Optix consists of three main components:
|
|
18
|
+
|
|
19
|
+
1. **Recipe Schema**: Defines what variables are included in a recipe
|
|
20
|
+
2. **Recipe Store**: The database where recipe data is stored
|
|
21
|
+
3. **Recipe Controller**: Manages loading, saving, and applying recipes
|
|
22
|
+
|
|
23
|
+
> [!NOTE]
|
|
24
|
+
> Recipes work by mapping values between a database table and variables in your project. The schema defines this mapping.
|
|
25
|
+
|
|
26
|
+
## Working with Recipe Schemas
|
|
27
|
+
|
|
28
|
+
A recipe schema links variables in your project model to columns in a database table. When recipes are loaded or saved, values are transferred between these locations.
|
|
29
|
+
|
|
30
|
+
### Creating a Recipe Schema manually
|
|
31
|
+
|
|
32
|
+
1. Add a Schema to the Recipes folder
|
|
33
|
+
2. Set the target node (typically the Model folder)
|
|
34
|
+
3. Set the store where recipes will be saved
|
|
35
|
+
4. Use the UI to select variables to include in the schema
|
|
36
|
+
|
|
37
|
+
### Modifying Recipe Schemas programmatically
|
|
38
|
+
|
|
39
|
+
Recipe schemas can be modified at runtime using NetLogic. This is useful when you need to dynamically change which variables are included in recipes.
|
|
40
|
+
|
|
41
|
+
```csharp
|
|
42
|
+
[ExportMethod]
|
|
43
|
+
public void UpdateRecipeSchema()
|
|
44
|
+
{
|
|
45
|
+
// Get the recipe schema from the project
|
|
46
|
+
var legacyRecipeSchema = Project.Current.Get<FTOptix.Recipe.RecipeSchema>("Recipes/MyRecipeSchema");
|
|
47
|
+
|
|
48
|
+
// Get the EditModel and Root objects
|
|
49
|
+
var editModel = legacyRecipeSchema.GetObject("EditModel");
|
|
50
|
+
var root = legacyRecipeSchema.GetObject("Root");
|
|
51
|
+
|
|
52
|
+
// Clear existing schema
|
|
53
|
+
if (editModel != null)
|
|
54
|
+
editModel.Children.ToList().ForEach(child => child.Delete());
|
|
55
|
+
if (root != null)
|
|
56
|
+
root.Children.ToList().ForEach(child => child.Delete());
|
|
57
|
+
|
|
58
|
+
// Add variables to the schema
|
|
59
|
+
var targetNode = InformationModel.Get(legacyRecipeSchema.TargetNode);
|
|
60
|
+
var speedVar = targetNode.GetVariable("MotorSpeed");
|
|
61
|
+
|
|
62
|
+
if (speedVar != null)
|
|
63
|
+
{
|
|
64
|
+
// Add to EditModel and Root
|
|
65
|
+
var editVar = InformationModel.MakeVariable("MotorSpeed", speedVar.DataType);
|
|
66
|
+
var rootVar = InformationModel.MakeVariable("MotorSpeed", speedVar.DataType);
|
|
67
|
+
editModel.Add(editVar);
|
|
68
|
+
root.Add(rootVar);
|
|
69
|
+
|
|
70
|
+
// Update database columns
|
|
71
|
+
var store = InformationModel.Get<Store>(legacyRecipeSchema.Store);
|
|
72
|
+
var table = store.Tables.Get(legacyRecipeSchema.BrowseName);
|
|
73
|
+
if (table != null)
|
|
74
|
+
{
|
|
75
|
+
var column = InformationModel.Make<StoreColumn>("MotorSpeed");
|
|
76
|
+
column.DataType = speedVar.DataType;
|
|
77
|
+
table.Columns.Add(column);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Adding hierarchical variables to a Recipe Schema
|
|
84
|
+
|
|
85
|
+
Variables in nested folders or objects require special handling. The code below demonstrates how to add variables from various locations in your project model:
|
|
86
|
+
|
|
87
|
+
```csharp
|
|
88
|
+
[ExportMethod]
|
|
89
|
+
public void AddVariablesToRecipeSchema()
|
|
90
|
+
{
|
|
91
|
+
// Get the recipe schema
|
|
92
|
+
var legacyRecipeSchema = Project.Current.Get<FTOptix.Recipe.RecipeSchema>("Recipes/MyRecipeSchema");
|
|
93
|
+
if (legacyRecipeSchema == null)
|
|
94
|
+
{
|
|
95
|
+
Log.Error("Recipe schema not found");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Get or create EditModel and Root
|
|
100
|
+
var editModel = legacyRecipeSchema.GetObject("EditModel") ?? InformationModel.MakeObject("EditModel");
|
|
101
|
+
var root = legacyRecipeSchema.GetObject("Root") ?? InformationModel.MakeObject("Root");
|
|
102
|
+
|
|
103
|
+
if (legacyRecipeSchema.GetObject("EditModel") == null)
|
|
104
|
+
legacyRecipeSchema.Add(editModel);
|
|
105
|
+
if (legacyRecipeSchema.GetObject("Root") == null)
|
|
106
|
+
legacyRecipeSchema.Add(root);
|
|
107
|
+
|
|
108
|
+
// Get the database table
|
|
109
|
+
var store = InformationModel.Get<Store>(legacyRecipeSchema.Store);
|
|
110
|
+
var table = store.Tables.Get(legacyRecipeSchema.BrowseName);
|
|
111
|
+
|
|
112
|
+
// Variables to add
|
|
113
|
+
var variablePaths = new List<string>
|
|
114
|
+
{
|
|
115
|
+
"Settings/Temperature",
|
|
116
|
+
"Settings/Speed",
|
|
117
|
+
"Settings/BatchSize"
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Add each variable to the schema
|
|
121
|
+
var targetNode = InformationModel.Get(legacyRecipeSchema.TargetNode);
|
|
122
|
+
foreach (var path in variablePaths)
|
|
123
|
+
{
|
|
124
|
+
AddVariableToSchema(targetNode, path, editModel, root, table);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private void AddVariableToSchema(IUANode targetNode, string path, IUAObject editModel,
|
|
129
|
+
IUAObject root, Table table)
|
|
130
|
+
{
|
|
131
|
+
// Get the variable
|
|
132
|
+
var variable = targetNode.GetVariable(path);
|
|
133
|
+
if (variable == null)
|
|
134
|
+
{
|
|
135
|
+
Log.Error($"Variable {path} not found");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Create path segments
|
|
140
|
+
var segments = path.Split('/');
|
|
141
|
+
var varName = segments.Last();
|
|
142
|
+
var folders = segments.Take(segments.Length - 1).ToArray();
|
|
143
|
+
|
|
144
|
+
// Create folders in EditModel and Root if needed
|
|
145
|
+
var currentEditFolder = editModel;
|
|
146
|
+
var currentRootFolder = root;
|
|
147
|
+
|
|
148
|
+
foreach (var folder in folders)
|
|
149
|
+
{
|
|
150
|
+
var editChildFolder = currentEditFolder.GetObject(folder);
|
|
151
|
+
if (editChildFolder == null)
|
|
152
|
+
{
|
|
153
|
+
editChildFolder = InformationModel.MakeObject(folder);
|
|
154
|
+
currentEditFolder.Add(editChildFolder);
|
|
155
|
+
}
|
|
156
|
+
currentEditFolder = editChildFolder;
|
|
157
|
+
|
|
158
|
+
var rootChildFolder = currentRootFolder.GetObject(folder);
|
|
159
|
+
if (rootChildFolder == null)
|
|
160
|
+
{
|
|
161
|
+
rootChildFolder = InformationModel.MakeObject(folder);
|
|
162
|
+
currentRootFolder.Add(rootChildFolder);
|
|
163
|
+
}
|
|
164
|
+
currentRootFolder = rootChildFolder;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Add variables to the folders
|
|
168
|
+
var editVar = InformationModel.MakeVariable(varName, variable.DataType);
|
|
169
|
+
var rootVar = InformationModel.MakeVariable(varName, variable.DataType);
|
|
170
|
+
currentEditFolder.Add(editVar);
|
|
171
|
+
currentRootFolder.Add(rootVar);
|
|
172
|
+
|
|
173
|
+
// Add column to the table
|
|
174
|
+
if (table != null)
|
|
175
|
+
{
|
|
176
|
+
var columnName = string.Join("/", segments);
|
|
177
|
+
var column = InformationModel.Make<StoreColumn>(columnName);
|
|
178
|
+
column.DataType = variable.DataType;
|
|
179
|
+
table.Columns.Add(column);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Populating a Recipe Schema
|
|
185
|
+
|
|
186
|
+
The following example demonstrates how to populate a recipe schema with variables from different locations within your project model:
|
|
187
|
+
|
|
188
|
+
```csharp
|
|
189
|
+
[ExportMethod]
|
|
190
|
+
public void PopulateRecipeSchema()
|
|
191
|
+
{
|
|
192
|
+
// List of tags with relative path from the root node to be added to the FTOptix.Recipe.RecipeSchema
|
|
193
|
+
var tagsToAdd = new List<string>
|
|
194
|
+
{
|
|
195
|
+
"Folder1/Variable3", // Variable in a folder
|
|
196
|
+
"Variable2", // Variable in the Model
|
|
197
|
+
"Object3/Object1/Variable2", // Variable in a nested object
|
|
198
|
+
"Object2/Variable1", // Variable in an object
|
|
199
|
+
"Object1" // Entire object (may contain other objects or variables)
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
//get the FTOptix.Recipe.RecipeSchema object
|
|
203
|
+
var legacyRecipeSchema = Project.Current.Get<FTOptix.Recipe.RecipeSchema>("Recipes/LegacyRecipeSchema1");
|
|
204
|
+
|
|
205
|
+
// Check if the FTOptix.Recipe.RecipeSchema exists and if the Store and TargetNode are set
|
|
206
|
+
if (legacyRecipeSchema == null ||
|
|
207
|
+
legacyRecipeSchema.Store == NodeId.Empty ||
|
|
208
|
+
legacyRecipeSchema.TargetNode == NodeId.Empty)
|
|
209
|
+
{
|
|
210
|
+
Log.Error("Invalid recipe schema configuration");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Get the root node of the Information Model
|
|
215
|
+
var rootNode = InformationModel.Get(legacyRecipeSchema.TargetNode);
|
|
216
|
+
|
|
217
|
+
// Process each tag
|
|
218
|
+
foreach (string path in tagsToAdd)
|
|
219
|
+
{
|
|
220
|
+
var node = rootNode.Get(path);
|
|
221
|
+
if (node == null)
|
|
222
|
+
{
|
|
223
|
+
Log.Error($"Node '{path}' not found");
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (node is IUAObject obj)
|
|
228
|
+
{
|
|
229
|
+
// Process all variables in the object
|
|
230
|
+
foreach (var childVar in obj.FindNodesByType<IUAVariable>())
|
|
231
|
+
AddNodeToSchema(childVar, legacyRecipeSchema);
|
|
232
|
+
}
|
|
233
|
+
else
|
|
234
|
+
{
|
|
235
|
+
// Process single variable
|
|
236
|
+
AddNodeToSchema(node, legacyRecipeSchema);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Modify an existing Recipe Schema programmatically
|
|
243
|
+
|
|
244
|
+
```csharp
|
|
245
|
+
/// <summary>
|
|
246
|
+
/// Add variables and corresponding store columns to an existing FTOptix.Recipe.RecipeSchema.
|
|
247
|
+
/// Inputs: two model variables present in the project (Model/Variable2, Model/Variable3).
|
|
248
|
+
/// This is a DesignTime helper typically invoked from a DesignTime NetLogic or exported method.
|
|
249
|
+
/// </summary>
|
|
250
|
+
[ExportMethod]
|
|
251
|
+
public void ModifyRecipeSchema()
|
|
252
|
+
{
|
|
253
|
+
// Get variables from the model
|
|
254
|
+
IUAVariable var2 = Project.Current.GetVariable("Model/Variable2");
|
|
255
|
+
IUAVariable var3 = Project.Current.GetVariable("Model/Variable3");
|
|
256
|
+
|
|
257
|
+
// Get the recipe schema to modify
|
|
258
|
+
FTOptix.Recipe.RecipeSchema legacyRecipeSchema = Project.Current.Get<FTOptix.Recipe.RecipeSchema>("Recipes/LegacyRecipeSchema1");
|
|
259
|
+
|
|
260
|
+
// Add variables to the EditModel (UI edit form)
|
|
261
|
+
IUAObject editModelObj = legacyRecipeSchema.GetObject("EditModel");
|
|
262
|
+
IUAVariable var2ToAddEditModel = InformationModel.MakeVariable(var2.BrowseName, var2.DataType);
|
|
263
|
+
IUAVariable var3ToAddEditModel = InformationModel.MakeVariable(var3.BrowseName, var3.DataType);
|
|
264
|
+
editModelObj.Add(var2ToAddEditModel);
|
|
265
|
+
editModelObj.Add(var3ToAddEditModel);
|
|
266
|
+
|
|
267
|
+
// Add variables to the Root (actual storage mapping)
|
|
268
|
+
IUAObject rootObj = legacyRecipeSchema.GetObject("Root");
|
|
269
|
+
IUAVariable var2ToAddRoot = InformationModel.MakeVariable(var2.BrowseName, var2.DataType);
|
|
270
|
+
IUAVariable var3ToAddRoot = InformationModel.MakeVariable(var3.BrowseName, var3.DataType);
|
|
271
|
+
rootObj.Add(var2ToAddRoot);
|
|
272
|
+
rootObj.Add(var3ToAddRoot);
|
|
273
|
+
|
|
274
|
+
// Create corresponding columns in the store table
|
|
275
|
+
var DB_Table_Columns = Project.Current.Get("DataStores/EmbeddedDatabase1/Tables/LegacyRecipeSchema1/Columns");
|
|
276
|
+
var TableColumn_Var2 = InformationModel.Make<StoreColumn>("/" + var2.BrowseName);
|
|
277
|
+
TableColumn_Var2.DataType = var2.DataType;
|
|
278
|
+
var TableColumn_Var3 = InformationModel.Make<StoreColumn>("/" + var3.BrowseName);
|
|
279
|
+
TableColumn_Var3.DataType = var3.DataType;
|
|
280
|
+
DB_Table_Columns.Add(TableColumn_Var2);
|
|
281
|
+
DB_Table_Columns.Add(TableColumn_Var3);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Clear EditModel content recursively
|
|
286
|
+
|
|
287
|
+
```csharp
|
|
288
|
+
/// <summary>
|
|
289
|
+
/// Helper methods to clear the EditModel of a recipe schema by resetting variables to default values.
|
|
290
|
+
/// Use with caution: this will set variables to empty/zero values depending on type.
|
|
291
|
+
/// </summary>
|
|
292
|
+
private void ClearEditModel(IUANode obj)
|
|
293
|
+
{
|
|
294
|
+
foreach (var item in obj.Children)
|
|
295
|
+
{
|
|
296
|
+
switch (item.NodeClass)
|
|
297
|
+
{
|
|
298
|
+
case NodeClass.Object:
|
|
299
|
+
// Recurse into nested objects
|
|
300
|
+
ClearEditModel(item);
|
|
301
|
+
break;
|
|
302
|
+
case NodeClass.Variable:
|
|
303
|
+
// Reset the variable value based on its current type
|
|
304
|
+
ResetVariableValue(item as IUAVariable);
|
|
305
|
+
break;
|
|
306
|
+
default:
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private void ResetVariableValue(IUAVariable iUAVariable)
|
|
313
|
+
{
|
|
314
|
+
var val = iUAVariable.Value.Value;
|
|
315
|
+
switch (val)
|
|
316
|
+
{
|
|
317
|
+
case string:
|
|
318
|
+
iUAVariable.Value = string.Empty;
|
|
319
|
+
break;
|
|
320
|
+
case int:
|
|
321
|
+
case short:
|
|
322
|
+
case long:
|
|
323
|
+
case float:
|
|
324
|
+
iUAVariable.Value = 0;
|
|
325
|
+
break;
|
|
326
|
+
case bool:
|
|
327
|
+
iUAVariable.Value = false;
|
|
328
|
+
break;
|
|
329
|
+
default:
|
|
330
|
+
iUAVariable.Value = 0;
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
> [!WARNING]
|
|
337
|
+
> When adding entire objects to a recipe schema, all variables within that object (including those in nested objects) will be included. Be careful with large object hierarchies as they might significantly increase the size of your recipe database.
|
|
338
|
+
|
|
339
|
+
## Working with Recipe Data at Runtime
|
|
340
|
+
|
|
341
|
+
The following examples demonstrate common recipe operations you might need to perform in your application.
|
|
342
|
+
|
|
343
|
+
> [!NOTE]
|
|
344
|
+
> Please see the `LegacyRecipesController.cs` file in the `Scripts` library of the FactoryTalk Optix IDE to see how to load, apply, create or update recipes at runtime.
|
|
345
|
+
|
|
346
|
+
### Importing/Exporting recipes to CSV
|
|
347
|
+
|
|
348
|
+
> [!NOTE]
|
|
349
|
+
> Please use the code in the `LegacyRecipesController.cs` file in the `Scripts` library of the FactoryTalk Optix IDE to import and export recipes to CSV format.
|
|
350
|
+
|
|
351
|
+
### Checking if a recipe exists
|
|
352
|
+
|
|
353
|
+
```csharp
|
|
354
|
+
[ExportMethod]
|
|
355
|
+
public bool RecipeExists(string recipeName)
|
|
356
|
+
{
|
|
357
|
+
var legacyRecipeSchema = Project.Current.Get<FTOptix.Recipe.RecipeSchema>("Recipes/LegacyRecipeSchema1");
|
|
358
|
+
if (legacyRecipeSchema == null || string.IsNullOrEmpty(recipeName))
|
|
359
|
+
return false;
|
|
360
|
+
|
|
361
|
+
var store = InformationModel.Get<Store>(legacyRecipeSchema.Store);
|
|
362
|
+
if (store == null)
|
|
363
|
+
return false;
|
|
364
|
+
|
|
365
|
+
var tableName = string.IsNullOrEmpty(legacyRecipeSchema.TableName) ? legacyRecipeSchema.BrowseName : legacyRecipeSchema.TableName;
|
|
366
|
+
|
|
367
|
+
// Query the database to check if the recipe exists
|
|
368
|
+
object[,] resultSet;
|
|
369
|
+
string[] header;
|
|
370
|
+
string query = $"SELECT * FROM \"{tableName}\" WHERE Name LIKE '{recipeName.Replace("'", "''")}'";
|
|
371
|
+
store.Query(query, out header, out resultSet);
|
|
372
|
+
|
|
373
|
+
return resultSet != null && resultSet.GetLength(0) > 0;
|
|
374
|
+
}
|
|
375
|
+
```
|