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:

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;

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");

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;
);