Calculation Code Examples
This page provides calculation code examples
1. How to add new record to Alarm Log Row table ?
// Automatically generated scaffolding for the calculation code
//
// Code name: no code name defined, put code name on the input box above this code editor
// List of variables that you can use based on parameters that you have added:
// CalcEquipment_Pump P1
using System.Linq;
using System;
namespace ABB.Vtrin.CalcEngine
{
public class CalcClass_PumpAlarmLogRow : CalcInstance
{
// put your constructor here
public void Calculate(CalcEquipment_Pump P1)
{
// put your calculation code here
WriteLine(P1.RPM.CurrentValue.Value.ToString());
WriteLine(P1.PathInstance.ToString());
var equipmentInstnace = P1.PathInstance.ToString();
var instnaceID = Driver.Classes["Path"].Instances.GetInstanceByName(equipmentInstnace).Id;
var propID = GetPropertyId(P1.EquipmentId.ToString(),"RPM");
WriteLine("Pump Instance ID is : "+instnaceID.ToString());
WriteLine("Pump RPM ID is : "+propID.ToString());
if(P1.PRESSURE.CurrentValue.Value>10){
var pathClass = Driver.Classes["AlarmLogRow"];
if(pathClass!=null){
var newInstance = pathClass.Instances.Add();
newInstance.SetRawPropertyValue("EventTime", DateTime.UtcNow);//this is GUID of M1 motor instance
newInstance.SetRawPropertyValue("Instance", instnaceID);//this is GUID of M1 motor instance
newInstance.SetRawPropertyValue("Property",propID);
pathClass.Instances.CommitChanges([newInstance]);
}
}
}
private System.Guid GetPropertyId(string equipmenttypeid, string propertyname)
{
var equs = Driver.Classes["Equipment"];
if (equs == null)
throw new System.ApplicationException("Class 'Equipment' not available");
var infos = Driver.Classes["EquipmentPropertyInfo"];
if (infos == null)
throw new System.ApplicationException("Class 'EquipmentPropertyInfo' not available");
var equ = equs.Instances.GetInstanceById(equipmenttypeid);
if (equ == null)
throw new System.ApplicationException($"Equipment type '{equipmenttypeid}' not found");
// Search from equipment and base equipments
for (; ; )
{
var def = infos.Instances.GetInstanceSet("Equipment=? and DisplayName=?", equ, propertyname);
if (def.Length != 0)
{
return (System.Guid)def[0].Id;
}
else
{
var baseequ = equ["Base"];
if (baseequ == null)
throw new System.ApplicationException($"Property name '{propertyname}' not found");
equ = (ABB.Vtrin.cDbClassInstance)baseequ;
}
}
}
}
}2. How to read history data from equipment property and write to another property ?
// Automatically generated scaffolding for the calculation code
// Code name: no code name defined, put code name on the input box above this code editor
// List of variables that you can use based on parameters that you have added:
// CalcEquipment_MOTOR motor
using System.Linq;
using System;
using System.Collections.Generic;
namespace ABB.Vtrin.CalcEngine
{
public class CalcClass_ReadAndWriteArrayDataType_1000 : CalcInstance
{
// put your constructor here
public void Calculate(CalcEquipment_MOTOR motor)
{
// put your calculation code here
DateTime startTime = DateTime.Now.AddMinutes(-5);
DateTime endTime = DateTime.Now;
var prop1 = motor.PROP1.FetchGraphData("", startTime, endTime,"StreamHistory");
WriteLine("Graph Data Points Count :: " + prop1.Count);
for(int i =0;i<prop1.Count;i++){
var xValue = Convert.ToDateTime(prop1.GetXValue(i));
var yValue = prop1.GetYValue(i);
motor.PROP_2.WriteValue(value, xValue.AddMilliseconds(i));
}
}
}
}3. Write data to OPC Event table based on a condition
// Automatically generated scaffolding for the calculation code
// Code name: no code name defined, put code name on the input box above this code editor
// List of variables that you can use based on parameters that you have added:
using System.Linq;
using System;
using System.Collections.Generic;
namespace ABB.Vtrin.CalcEngine
{
public class CalcClass_WriteDataToOPCEventTable : CalcInstance
{
// put your constructor here
public void Calculate(CalcEquipment_MOTOR motor)
{
// put your calculation code here
if(motor.RPM.CurrentValue.Value >= 1500){
var pathClass = driver.Classes["OpcEvent"];
var newInstance = pathClass.Instances.Add();
newInstance.SetRawPropertyValue("EventTime", DateTime.UtcNow);
newInstance.SetRawPropertyValue("Source", "Automation Test");
newInstance.SetRawPropertyValue("Message", uniqueName);
pathClass.Instances.CommitChanges(new[] { newInstance });
}
}
}
}4. Read data from third part APIs using calculation.
This example reads data from a third party API and parses the data and writes to a variable.
// Automatically generated scaffolding for the calculation code
//
// Code name: no code name defined, put code name on the input box above this code editor
// List of variables that you can use based on parameters that you have added:
// CalcVariable<double> temperature
using System;
using System.Globalization;
using System.Linq;
using System.Xml;
namespace ABB.Vtrin.CalcEngine
{
public class CalcClass_LatestTemperatureFetcher : CalcInstance
{
// put your constructor here
public void Calculate(CalcVariable<double> temperature)
{
// put your calculation code here
// Load to XmlDocument object
using (var xmlReader = new XmlTextReader("http://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::observations::weather::simple&place=helsinki")
{
DtdProcessing = DtdProcessing.Ignore
})
{
var xmlDocument = new XmlDocument();
xmlDocument.Load(xmlReader);
var namespaceManager = new XmlNamespaceManager(xmlDocument.NameTable);
namespaceManager.AddNamespace("wfs", "http://www.opengis.net/wfs/2.0");
namespaceManager.AddNamespace("BsWfs", "http://xml.fmi.fi/schema/wfs/2.0");
// Get all <BsWfsElement>s that contain <ParameterName> with content t2m = air temperature
// t2m param is air temperature: http://opendata.fmi.fi/meta?observableProperty=observation¶m=t2m&language=eng
var xmlNodes = xmlDocument.SelectNodes("//BsWfs:BsWfsElement[BsWfs:ParameterName and BsWfs:ParameterName[text()='t2m']]", namespaceManager);
if (xmlNodes is null || xmlNodes.Count == 0)
{
throw new Exception("Unable to get <BsWfsElement>s from xml.");
}
// Order <BsWfsElement>s by <BsWfs:Time> value and
// get <BsWfs:ParameterValue> and <BsWfs:Time> element value
(DateTime date, double temperature)? latestMeasurement = xmlNodes
.OfType<XmlElement>()
.Select(e => (
date: e.SelectSingleNode("BsWfs:Time", namespaceManager)?.InnerText,
temperature: e.SelectSingleNode("BsWfs:ParameterValue", namespaceManager)?.InnerText)
)
.Where(v => !string.IsNullOrWhiteSpace(v.date) && !string.IsNullOrWhiteSpace(v.temperature))
.Select(v => (
date: DateTime.Parse(v.date, CultureInfo.InvariantCulture).ToUniversalTime(),
temperature: double.Parse(v.temperature, NumberStyles.Number, CultureInfo.InvariantCulture)
))
.OrderByDescending(v => v.date)
.FirstOrDefault();
if (!latestMeasurement.HasValue)
{
throw new Exception($"Unable to parse <BsWfs:Time> and <BsWfs:ParameterValue> elements from {xmlNodes.Count} <BsWfsElement> elements.");
}
//temperature = latestMeasurement.Value.temperature;
//date = latestMeasurement.Value.date;
temperature.SetCurrentValue(latestMeasurement.Value.temperature, latestMeasurement.Value.date);
}
}
}
}// Automatically generated scaffolding for the calculation code
//
// Code name: no code name defined, put code name on the input box above this code editor
// List of variables that you can use based on parameters that you have added:
// CalcVariable<double> ElectricityPrice
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
namespace ABB.Vtrin.CalcEngine
{
public class CalcClass_CurrentElectricityPriceFetcher : CalcInstance
{
// put your constructor here
public void Calculate(CalcVariable<double> ElectricityPrice)
{
// put your calculation code here
using (var webClient = new WebClient())
{
// Download JSON
var jsonString = webClient.DownloadString("https://elspotcontrol.netlify.app/spotprices-v01-FI.json");
var regexp = new Regex(@"{""time"": ""([^""]+)"", ""price"": (\d+\.\d+)}");
var matches = regexp.Matches(jsonString);
var results = new List<(double price, DateTime date)>();
foreach (var item in matches.OfType<Match>())
{
results.Add((
price: double.Parse(item.Groups[2].Value, NumberStyles.Number, CultureInfo.InvariantCulture) / 10,
date: DateTime.Parse(item.Groups[1].Value, CultureInfo.InvariantCulture).ToUniversalTime()
));
}
var currentTime = DateTime.UtcNow;
var (price, date) = results.FirstOrDefault(r => r.date.Date == currentTime.Date && (r.date.Hour == currentTime.Hour || r.date.Hour == currentTime.Hour - 1));
// currentElectricityPrice = price;
ElectricityPrice.SetCurrentValue(price, currentTime);
}
}
}
}5. Totalizer calculation of Steam Flow example
Lets assumes Steam Flow Data is updated for every 1 second for a variable (Steam_Flow) and being collected for 1 minute. And let's sum the data points for 1 minute duration and write to a new variable 'Steam_Flow_Totalizer'
// Automatically generated scaffolding for the calculation code
//
// Code name: no code name defined, put code name on the input box above this code editor
// List of variables that you can use based on parameters that you have added:
// CalcVariable<double> Temperature, CalcVariable<double> TotalizedTemperature
using System.Linq;
using System;
namespace ABB.Vtrin.CalcEngine
{
public class CalcClass_calc_1 : CalcInstance
{
// put your constructor here
public void Calculate(CalcVariable<double> Steam_Flow, CalcVariable<double> Steam_Flow_Totalizer)
{
// put your calculation code here
DateTime time1 = DateTime.Now.AddMinutes(-1);
DateTime time2 = DateTime.Now.AddMinutes(0);
var sum = Steam_Flow.GetSum(time1,time2,"StreamHistory");
WriteLine("SUM :: "+sum.Value.ToString());
Steam_Flow_Totalizer.CurrentValue = sum.Value;
}
}
}6. How to fetch Max and Min value of a Tag using calculation
This example helps the user to fetch Max Value and Min Value of a Tag using the calculation.
// Automatically generated scaffolding for the calculation code
//
// Code name: no code name defined, put code name on the input box above this code editor
// List of variables that you can use based on parameters that you have added:
// CalcVariable<double> TAG1
using System.Linq;
using System;
namespace ABB.Vtrin.CalcEngine
{
public class CalcClass_FetchValueMinAndMaxOfVariable : CalcInstance
{
// put your constructor here
public void Calculate(CalcVariable<double> TAG1)
{
// put your calculation code here
var instance = Driver.Classes["Tag"].Instances.GetInstanceSet($"DisplayName = "+TAG1.Name).FirstOrDefault();
if(instance != null){
var min = instance["ValueDisplayMin"];
var max = instance["ValueDisplayMax"];
if(TAG1.CurrentValue.Value > Convert.ToDouble(min)){
WriteLine("Current value of " + TAG1.Name + " is off the Min limit " + min.ToString());
}
}
}
}
}Updated 5 months ago
