Overview
The Scripting Reference provides comprehensive documentation for developing custom logic in FrameworX 10.1. With support for multiple programming languages including C#, VB.NET, Python, and JavaScript, you can implement complex calculations, automation logic, and integrations. This guide covers syntax, APIs, best practices, and practical examples for all scripting scenarios.
...
Info | ||
---|---|---|
| ||
→ Scripts Module: follow this link with information about the Scripts Modules This section focus on the usage of the programming, not the Script Modules itself. This section is recommended to be used, only after the understanding of the Scripts Module. |
...
Supported Languages
Language Comparison
Language | Use Cases | Performance | Learning Curve | Key Features |
---|---|---|---|---|
C# | Complex logic, performance-critical | Excellent | Moderate | Full .NET access, strongly typed |
VB.NET | Legacy systems, simple logic | Excellent | Easy | Familiar syntax, .NET access |
Python | Data analysis, ML, scripting | Good | Easy | Libraries, readable syntax |
JavaScript | Client-side, expressions ,HTML5 (*1) | Good | Easy | Web integration, JSON |
...
Info | ||
---|---|---|
| ||
JavaScript is available only in HTML5-only, displays.  Prefer always to the Portable Pages, which allows the configuration on Desktop Rich Clients (.NET WPF) and Web/Mobile clients (WebAssembly). Keep JavaScript and HTML5 only required for code compatibility  or use of external HTML5 controls. |
Language Selection Guide
Decision Tree:
Need maximum performance? => C#
Need higher level of runtime security & Reliably => C#
Legacy VB code? => VB.NET
Data science/ML? => Python
Client-side logic? => C# & Python server classes
Simple expressions => any language. Platform expression editor can parse different languages.
...
Script Types
Tasks (Scheduled Scripts)
Tasks execute on schedules or triggers:
...
// C# Task Example
// Read current values
double production = @Tag.Production.Counter;
DateTime shiftStart = @Tag.Shift.StartTime;
// Calculate metrics
    double hours = (DateTime.Now - shiftStart).TotalHours;
double rate = count / hours;
// Update tags
@Tag.KPI.ProductionRate = rate;
@Tag.KPI.LastUpdate = DateTime.Now;
// Log to database
@Script.Class.Util.LogToDatabase(rate);
 Â
Classes (Reusable Libraries)
Classes provide reusable functions:
...
// C# Class Library: EngineeringCalcs
// Flow calculation
public static double CalculateFlow(double dp, double k)
{
return k * Math.Sqrt(dp);
}
// Temperature conversion
public static double CelsiusToFahrenheit(double celsius)
{
return (celsius * 9.0 / 5.0) + 32;
}
// Pressure conversion
public static double PSIToBar(double psi)
{
return psi * 0.0689476;
}
// Tank volume
public static double CylindricalTankVolume(double diameter, double level)
{
double radius = diameter / 2;
return Math.PI * radius * radius * level;
}
Expressions (Inline Calculations)
Expressions are single-line calculations:
...
// JavaScript Expressions
// Conditional logic
@Tag.Pump.Status = @Tag.Pump.Running ? "Running" : "Stopped"
// Mathematical calculation
@Tag.Tank.Volume = Math.PI * Math.pow(@Tag.Tank.Radius, 2) * @Tag.Tank.Level
// String manipulation
@Tag.Display.Message = "Temperature: " + @Tag.Temp.Value.toFixed(1) + "°C"
// Date/time calculation
@Tag.Batch.Duration = (Date.now() - @Tag.Batch.StartTime) / 1000 / 60
Display Scripts (UI Event Handlers)
Scripts triggered by UI events:
...
// C# Display Script
public void OnButtonClick(object sender, EventArgs e)
{
// Validate user input
if (!ValidatePermissions())
{
ShowMessage("Access Denied");
return;
}
// Execute command
@Tag.Equipment.StartCommand = true;
// Log action
LogUserAction("Start button pressed");
// Update display
RefreshDisplay();
}
private bool ValidatePermissions()
{
return @Tag.Security.UserLevel >= 2;
}
...
Tag Access
Reading and Writing Tags
C# Tag Access
csharp
// Reading tags
double temperature = @Tag.Process.Temperature;
bool motorRunning = @Tag.Motor1.Running;
string batchID = @Tag.Batch.ID;
DateTime timestamp = @Tag.System.CurrentTime;
// Writing tags
@Tag.Setpoint.Value = 75.5;
@Tag.Pump.Start = true;
@Tag.Message.Text = "Process started";
// Array access
double[] values = @Tag.Data.Array;
@Tag.Data.Array[0] = 100;
// Quality and timestamp
TagQuality quality = @Tag.Process.Temperature.Quality;
DateTime lastUpdate = @Tag.Process.Temperature.Timestamp;
Python Tag Access
python
# Reading tags
temperature = @Tag.Process.Temperature
motor_running = @Tag.Motor1.Running
batch_id = @Tag.Batch.ID
# Writing tags
@Tag.Setpoint.Value = 75.5
@Tag.Pump.Start = True
@Tag.Message.Text = "Process started"
# Array operations
import numpy as np
values = np.array(@Tag.Data.Array)
mean_value = np.mean(values)
@Tag.Statistics.Mean = mean_value
# Bulk operations
tags_to_read = ['Tag1', 'Tag2', 'Tag3']
values = @Tag.ReadMultiple(tags_to_read)
Tag Properties and Methods
csharp
// Tag properties
public class TagProperties
{
// Basic properties
string Name { get; }
object Value { get; set; }
TagQuality Quality { get; }
DateTime Timestamp { get; }
// Extended properties
double Min { get; set; }
double Max { get; set; }
string Units { get; }
string Description { get; }
// Methods
void ForceValue(object value);
void Subscribe(Action<TagChangeEvent> handler);
void Unsubscribe();
bool WriteWithConfirm(object value, int timeout);
}
...
Database Operations
SQL Database Access
csharp
// C# Database Operations
public class DatabaseScript
{
public void ReadFromDatabase()
{
// Simple query
var result = @Dataset.Query("SELECT * FROM Production WHERE Date = TODAY");
// Parameterized query
var parameters = new Dictionary<string, object>
{
{ "StartDate", DateTime.Today },
{ "EndDate", DateTime.Now }
};
var data = @Dataset.ExecuteQuery(
"SELECT * FROM Production WHERE Timestamp BETWEEN @StartDate AND @EndDate",
parameters
);
// Process results
foreach (var row in data.Rows)
{
@Tag.Production.Count = row["Count"];
@Tag.Production.Quality = row["Quality"];
}
}
public void WriteToDatabase()
{
// Insert data
@Dataset.Execute(
"INSERT INTO BatchRecords (BatchID, StartTime, Product) VALUES (@ID, @Time, @Product)",
new {
ID = @Tag.Batch.ID,
Time = DateTime.Now,
Product = @Tag.Batch.Product
}
);
// Update data
@Dataset.Execute(
"UPDATE Equipment SET RunHours = @Hours WHERE ID = @EquipID",
new {
Hours = @Tag.Motor.RunHours,
EquipID = @Tag.Motor.ID
}
);
}
}
Transaction Management
csharp
// Transaction example
public void ExecuteTransaction()
{
using (var transaction = @Dataset.BeginTransaction())
{
try
{
// Multiple operations in transaction
@Dataset.Execute("INSERT INTO Orders ...", transaction);
@Dataset.Execute("UPDATE Inventory ...", transaction);
@Dataset.Execute("INSERT INTO Audit ...", transaction);
// Commit if all successful
transaction.Commit();
}
catch (Exception ex)
{
// Rollback on error
transaction.Rollback();
@Tag.Error.Message = ex.Message;
}
}
}
...
File Operations
Reading and Writing Files
csharp
// C# File Operations
public class FileOperations
{
public void ReadCSV()
{
string path = @"C:\Data\production.csv";
if (File.Exists(path))
{
var lines = File.ReadAllLines(path);
foreach (var line in lines.Skip(1)) // Skip header
{
var values = line.Split(',');
ProcessCSVLine(values);
}
}
}
public void WriteReport()
{
var report = new StringBuilder();
report.AppendLine($"Production Report - {DateTime.Now}");
report.AppendLine($"Total: {@Tag.Production.Total}");
report.AppendLine($"Good: {@Tag.Production.Good}");
report.AppendLine($"Reject: {@Tag.Production.Reject}");
File.WriteAllText(@"C:\Reports\daily.txt", report.ToString());
}
public void AppendLog()
{
string logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss},{@Tag.Process.Value}\n";
File.AppendAllText(@"C:\Logs\process.log", logEntry);
}
}
...
Communication Functions
Web Services and APIs
csharp
// REST API Calls
public class APIIntegration
{
private HttpClient client = new HttpClient();
public async Task GetDataFromAPI()
{
try
{
// GET request
var response = await client.GetAsync("https://api.example.com/data");
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
dynamic data = JsonConvert.DeserializeObject(json);
@Tag.External.Value = data.value;
@Tag.External.Status = data.status;
}
}
catch (Exception ex)
{
@Tag.Error.API = ex.Message;
}
}
public async Task PostDataToAPI()
{
var payload = new
{
timestamp = DateTime.Now,
value = @Tag.Process.Value,
quality = @Tag.Process.Quality
};
var json = JsonConvert.SerializeObject(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.example.com/data", content);
@Tag.API.LastPost = response.StatusCode.ToString();
}
}
Email Notifications
csharp
// Email Functions
public class EmailScript
{
public void SendAlarmEmail()
{
var email = new EmailMessage
{
To = "operator@company.com",
Subject = $"Alarm: {@Tag.Alarm.Description}",
Body = $@"
Alarm Active: {@Tag.Alarm.Description}
Time: {DateTime.Now}
Value: {@Tag.Alarm.Value}
Priority: {@Tag.Alarm.Priority}
Please acknowledge at HMI.
",
IsHtml = false
};
@System.SendEmail(email);
}
}
...
Error Handling
Exception Management
csharp
// Comprehensive Error Handling
public class ErrorHandling
{
public void SafeOperation()
{
try
{
// Risky operation
double result = Calculate();
@Tag.Result.Value = result;
}
catch (DivideByZeroException ex)
{
// Specific exception handling
@Tag.Error.Type = "Division Error";
@Tag.Error.Message = "Cannot divide by zero";
LogError(ex);
}
catch (Exception ex)
{
// General exception handling
@Tag.Error.Type = "General Error";
@Tag.Error.Message = ex.Message;
LogError(ex);
}
finally
{
// Always execute
@Tag.Process.Calculating = false;
}
}
private void LogError(Exception ex)
{
var errorLog = new
{
Timestamp = DateTime.Now,
Type = ex.GetType().Name,
Message = ex.Message,
StackTrace = ex.StackTrace,
User = @Tag.System.CurrentUser
};
@Dataset.Execute(
"INSERT INTO ErrorLog (Time, Type, Message, Stack, User) VALUES (@Time, @Type, @Msg, @Stack, @User)",
errorLog
);
}
}
...
Performance Optimization
Best Practices for Script Performance
csharp
// Performance Optimized Script
public class OptimizedScript
{
// Cache frequently used values
private static Dictionary<string, double> cache = new Dictionary<string, double>();
// Batch operations
public void BatchUpdate()
{
// Bad: Individual writes
// for (int i = 0; i < 100; i++)
// @Tag.Array[i] = Calculate(i);
// Good: Batch write
double[] values = new double[100];
for (int i = 0; i < 100; i++)
values[i] = Calculate(i);
@Tag.Array = values;
}
// Efficient loops
public void EfficientLoop()
{
// Pre-calculate invariants
double factor = @Tag.Config.Factor;
double offset = @Tag.Config.Offset;
var values = @Tag.Raw.Array;
var results = new double[values.Length];
// Use for instead of foreach for arrays
for (int i = 0; i < values.Length; i++)
{
results[i] = values[i] * factor + offset;
}
@Tag.Scaled.Array = results;
}
// Minimize tag access
public void MinimizeTagAccess()
{
// Bad: Multiple tag reads
// if (@Tag.Process.Mode == 1 && @Tag.Process.Mode != 2)
// Good: Single read
int mode = @Tag.Process.Mode;
if (mode == 1 && mode != 2)
{
// Process
}
}
}
...
Debugging Scripts
Debug Techniques
csharp
// Debugging Methods
public class DebugScript
{
public void DebugExample()
{
// Console output (appears in logs)
Console.WriteLine($"Debug: Starting process at {DateTime.Now}");
// Conditional debugging
#if DEBUG
Console.WriteLine("Debug mode - detailed logging enabled");
var stopwatch = Stopwatch.StartNew();
#endif
// Debug tags
@Tag.Debug.LastRun = DateTime.Now;
@Tag.Debug.ExecutionTime = stopwatch.ElapsedMilliseconds;
// Breakpoint (in Designer test mode)
System.Diagnostics.Debugger.Break();
// Trace information
Trace.WriteLine("Trace: Process completed");
Trace.Assert(@Tag.Value > 0, "Value should be positive");
}
}
...
Script Examples Library
Common Calculations
csharp
// Standard Industrial Calculations
public static class IndustrialCalcs
{
// PID Controller
public static double PID(double setpoint, double processValue,
ref double integral, ref double lastError,
double kp, double ki, double kd, double dt)
{
double error = setpoint - processValue;
integral += error * dt;
double derivative = (error - lastError) / dt;
lastError = error;
return kp * error + ki * integral + kd * derivative;
}
// Moving Average
public static double MovingAverage(Queue<double> window, double newValue, int windowSize)
{
window.Enqueue(newValue);
if (window.Count > windowSize)
window.Dequeue();
return window.Average();
}
// Rate of Change
public static double RateOfChange(double currentValue, double lastValue, double timeInterval)
{
return (currentValue - lastValue) / timeInterval;
}
// Totalization
public static double Totalize(double flow, double timeInterval, ref double total)
{
total += flow * timeInterval;
return total;
}
}
Data Processing
python
# Python Data Analysis Script
import numpy as np
import statistics
def analyze_batch_data():
# Get array data
temperatures = @Tag.Batch.TemperatureArray
pressures = @Tag.Batch.PressureArray
# Statistical analysis
@Tag.Stats.TempMean = np.mean(temperatures)
@Tag.Stats.TempStdDev = np.std(temperatures)
@Tag.Stats.TempMin = np.min(temperatures)
@Tag.Stats.TempMax = np.max(temperatures)
# Find outliers
z_scores = np.abs((temperatures - np.mean(temperatures)) / np.std(temperatures))
outliers = np.where(z_scores > 3)[0]
@Tag.Stats.OutlierCount = len(outliers)
# Correlation
correlation = np.corrcoef(temperatures, pressures)[0, 1]
@Tag.Stats.TempPressureCorrelation = correlation
# Quality determination
if @Tag.Stats.TempStdDev < 2.0 and len(outliers) == 0:
@Tag.Batch.Quality = "Good"
else:
@Tag.Batch.Quality = "Review Required"
...
Script Security
Security Best Practices
csharp
// Secure Scripting Practices
public class SecureScript
{
// Input validation
public void ValidateInput(string userInput)
{
// Sanitize input
userInput = userInput.Trim();
// Validate format
if (!Regex.IsMatch(userInput, @"^[a-zA-Z0-9_]+$"))
{
throw new ArgumentException("Invalid input format");
}
// Check length
if (userInput.Length > 50)
{
throw new ArgumentException("Input too long");
}
// SQL injection prevention (use parameters)
@Dataset.Execute(
"SELECT * FROM Table WHERE Name = @Name",
new { Name = userInput }
);
}
// Permission checking
public void SecureOperation()
{
// Check user permission
if (@Tag.Security.UserLevel < 3)
{
@Tag.Error.Message = "Insufficient permissions";
LogSecurityEvent("Unauthorized access attempt");
return;
}
// Execute privileged operation
ExecutePrivilegedOperation();
}
// Audit logging
private void LogSecurityEvent(string action)
{
@Dataset.Execute(
"INSERT INTO SecurityLog (Time, User, Action, Result) VALUES (@Time, @User, @Action, @Result)",
new {
Time = DateTime.Now,
User = @Tag.System.CurrentUser,
Action = action,
Result = "Denied"
}
);
}
}
...
Next Steps
Additional Resources
- .NET API Reference - Detailed .NET framework access
- Python API Reference - Python-specific functions
- Built-in Functions - Standard function library
- Code Examples - Complete script examples
...
AI Assistant Data
<details> <summary>Structured Information for AI Tools</summary>
...