Skriptfunktion i Energiportal, IMC, CCS och liknande
Claystermiljön har en inbyggd skriptmotor som kan användas för att skapa mer avancerade funktioner i en del sammanhang. Det är ett programmeringsspråk för att göra beräkningar med längre formler och/eller i flera steg. Exempel är AQ, KPI:er och lastpunkter.
Hur får man indata till script?
Indata till skriptet beror på var det används. T ex i en AQ kan man använda de namn på ingångarna som man deklarerat. Man har tillgång till aktuell tid då skriptet körs, ”Now”.
Exempel:
- Igår samma tid: Now.AddDays(-1)
- Dagens datum: Now.Date
Utdata från skript
Resultatet av den sista tilldelning som görs blir skriptets utdata. T ex skriptet:
x := 4;
y := x*2;
Utdata blir 8
Saker som är lätt att göra fel på då man skriver sin funktion
Att tilldela ett värde: T ex
x := 3;
Bara ’=’ används för jämförelse, ’:=’ används för tilldelning.
Exempel villkorssats:
if(a > 3) (y := 2; z :0 3;);
if(a>3) then x := 2 else x:=1;
if(a>3) x := 2 else x:=1;
- Man kan gruppera satser med {}, eller med ().
- Efter slutparentes ska det vara ’;’.
Tilldela en text:
namn := ’pelle’;
eller
namn := ”pelle”;
är samma sak.
Tilldela en array/vektor:
siffror := [1, 2, 3, 4];
Omvandla en text till en siffra
Om man har en textsträng och vill tolka talet som står där:
goal:=System.Int32.Parse(text);
Öka med ett: Man kan öka ett tal med ett genom:
++x;
Detta fungerar dock inte för ett element i en vektor, alltså
++v[3]; // Fungerar INTE
fungerar INTE, skriv istället
v[3] := v[3]+1;
Dela en text
Dela en text i delar med något särskilt skiljetecken kan man göra så här:
delim := ["|"];
tmp := text.Split(delim, System.StringSplitOptions.RemoveEmptyEntries);
(Denna lite krångliga konstruktion beror på att vi inte kan deklarera en enskild bokstav.)
Loggning
För felsökning eller annat, skriv till händelselogg. Man kan skriva till systemets händelselogg (syns i t ex CMT) så här:
Message := "Samples: " + IndexSamples.ToString();
Clayster.Library.EventLog.Log.Information(Message, Clayster.Library.EventLog.EventLevel.Medium, "KPI","Scriptinfo");
- Message: logtexten
- Clayster.Library.EventLog.EventLevel.Medium: Nivå
- ”KPI”: Objekt
- ”Scriptinfo”: Ämne
Städa bort dessa utskrifter då de inte behövs längre, för att inte belasta loggfunktionen i onödan!
Tips och tricks
Try - catch
Om man är osäker på om en egenskap finns, eller om en text verkligen innehåller en siffra, kan man använda try-catch. Då kan skriptet så att säga prova en operation, och om det misslyckas hanteras det utan att skriptet kraschar. T ex:
try
(
goal:=System.Int32.Parse(text);
)
catch
(
goal := 0;
)
finally
if(goal > 0) then
...
(Här försöker vi tolka "text" som siffra. Om det misslyckas sätts "goal" till 0, och skriptet fortsätter.)
Läsning av historisk data
Det är möjligt att från ett skript i t ex en AQ att läsa ut data från historiken. Nedan ett expempel där alla värden av "Value" för en nod "Object.AV.Temp Ref" läses ut för de senaste 6 timmarna, och returnerar medelvärdet. Med lite uppenbara ändringar bör du kunna anpassa detta till dina behov i många fall.
fromDate := Now.AddHours(-6);
toDate := Now;
nodeId := 'Object.AV.Temp Ref';
fieldSink := "Localhost";
user := Clayster.Library.Abstract.Security.User.AllPrivileges;
res := 0.0;
// set up parameters for field sink read, and get data vector:
fieldSink := Clayster.Library.Entities.DataMining.Sinks.FieldSinks.GetFieldSink(fieldSink , user);
parameters := fieldSink.GetReadoutParameters();
interoperability := fieldSink.GetReadoutParameterInteroperability();
interoperability.SetOldTimepointLimit(parameters, fromDate);
interoperability.SetNewTimepointLimit(parameters, toDate);
interoperability.SetNodesLimit(parameters, [nodeId]);
interoperability.SetBooleanValues(parameters, Clayster.Library.Entities.DataMining.Sinks.BooleanReadoutMode.None);
interoperability.SetDateTimeValues(parameters, false);
interoperability.SetStringValues(parameters, false);
interoperability.SetTimeSpanValues(parameters, false);
interoperability.SetNumericalValues(parameters, true);
interoperability.SetFieldsLimit(parameters, ["Value"]);
// do the read from field sink:
result:=fieldSink.ReadoutSynchronous(parameters);
// calculate average:
j := 0;
x := 0.0; n := 0; sum := 0.0;
while(j < result.Length) do (
tmp :=result[j].ValueString.Split(null, 2, System.StringSplitOptions.RemoveEmptyEntries)[0];
if(System.Double.TryParse(tmp, x))
(
sum := sum + x;
n := n + 1;
);
j := j+1;
);
if(n > 0)
(
res := sum/n;
);