cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Stay updated on what is happening on the PTC Community by subscribing to PTC Community Announcements. X

Indirectly Referencing Thing Properties in Script

jhemper
2-Explorer

Indirectly Referencing Thing Properties in Script

I am looking for a way to iterate through a number of similarly named properties in an service to count the number of current alarms. I am not a JavaScript expert and have tried the following script but it does not seem to work:

me.z_AlarmCount = 0
for (var i=301;i<396;i++)
var n = i.toString()
    me.DebugString = "me.Alarm_CCP_Boiler_" + n;

    if (("me.Alarm_CCP_Boiler_" + n) == 1)
    {
        me.z_AlarmCount = me.z_AlarmCount + 1;
    }
}
  
Any assistance or advise would be appreciated.

Many Thanks

Jan Hemper
InVMA

13 REPLIES 13
AdamR
14-Alexandrite
(To:jhemper)

Instead of "me.Alarm_CCP_Boiler_" + n

Use me["Alarm_CCP_Boiler_" + n]

AdamR
14-Alexandrite
(To:jhemper)

So full script would be...

me.z_AlarmCount = 0for (var i=301;i<396;i++)var n = i.toString()    me.DebugString = "me.Alarm_CCP_Boiler_" + n;{       if ((me["Alarm_CCP_Boiler_" + n]) == 1)    {        me.z_AlarmCount = me.z_AlarmCount +1;    }}



adam11
7-Bedrock
(To:jhemper)

Hi Jan,

If I understand you correctly, you want to count the number of occurrences for properties prefixed with Alarm_CCP_Boiler, which will give you the number of alarms. However, based on your for loop, it seems you're only interested in a subset of these alarms?


If you simply want to count the number of occurrences for properties prefixed with Alarm_CCP_Boiler:

<br>

result = me.GetPropertyDefinitions(); // Get Properties for me


var params = 

{

  inclusive: true, // Include Matched Rows

  t: result, // Infotable to Filter

  pattern: "Alarm_CCP_Boiler" + "%", // Pattern to Match (% is wildcard)

  fieldName: "name" // Property Name Field Returned by GetPropertyDefinitions()

};


result = Resources["InfoTableFunctions"].LikeFilter(params); // Filter Properties

me.z_AlarmCount = result.getRowCount(); // Count # of Alarms


Will this work? Or are you interested in only a subset of these alarms?


Thanks,

Adam T



jhemper
2-Explorer
(To:jhemper)

Many thanks guys, both of these comments are very useful and will help me to achieve exactly what I need. Just out of interest are the various functions available as server side resources documented anywhere, the Resources["InfoTableFunctions"].xxx seems extremely powerful (as I guess are the other resources) but I have just been looking and was struggling to find the documentation.

Once again, many thanks

JanH


adam11
7-Bedrock
(To:jhemper)

Hi Jan,

You can view documentation for Resources in the wiki – the relevant entry is entitled "5.07 Resources". For a quick view of all Resources (along with their code snippets) from +Composer, +check out the Snippets tab in the Script Editor.


– Adam



jhemper
2-Explorer
(To:jhemper)

Hi Adam,

Thanks for this, I have now managed to find the documentation for the resources. Could I ask one more question on this thread please. What I am actually trying to do is described below:

1. I have a number of parameters that are prefixed with Alarm_CCP_Boiler_, these parameters relate to alarms in a particular part of a plant.
2. Our client has asked us to display an active alarms table containing date of last change of the particular property, property name and property description for all properties with a current value of 1.

Could you give some advise on the recommended way to implement this type of functionality.

Once again, many thanks

Jan



riaanl
7-Bedrock
(To:jhemper)

Hey Jan,

I assume you just need to display the properties (with the date/description), and you do not need to perform automatic processing and storage of the property changing.  If this assumption is correct, then the following script should be a good starting point. 


If there is a need for historical storage of these alarms, then you could leverage the 'DataChange' event and write a subscription which stores the property values to either a stream or a datatable.


Here is the aforementioned script.  Please note, I used a custom dataShape called AlarmPropertiesDataShape which you would either have to create or change within the script.

////////

// Create the result infotable from a custom datashape

// This datashape contains:

// - Name

// - Value

//  - Description

//  - Time

// CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(AlarmPropertiesDataShape)

var result = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({

infoTableName : "InfoTable",

dataShapeName : "AlarmPropertiesDataShape"

});


// Get the Property values with the time, value, and quality (VTQ)

// The VTQ results for each property is an infotable within each property column

// result: INFOTABLE dataShape: "undefined"

var propertiesVTQ = me.GetPropertyValuesVTQ();


// Loop through the infotable columns (the properties), and if it meets the criteria, add it to the result infotable.

var columnName = "";

var infotableColumns = Object.keys(propertiesVTQ.rows[0]);

for (var key in infotableColumns) {

    columnName = String(infotableColumns[key]);


    // propertiesVTQ (from GetPropertyValuesVTQ()) will always return a single row, so it is safe to reference that row using index 0.

    // Since we have the column name, we can just use bracket notation to reference the specific column within that row  ==> propertiesVTQ.rows[0][columnName]

    // Additionally, we know that the value for this column is an infotable, so its single row can be referenced using the rows object:  (propertiesVTQ.rows[0][columnName]).rows[0]

    var vtqInfotableForProperty = (propertiesVTQ.rows[0][columnName]).rows[0];

    

    // Within this vtq row, you will have a value, time and a quality.

    // if the value is one, add the new row to your result infotable

    if (vtqInfotableForProperty.value == 1) {

        var newRow = {};

        newRow.Name = columnName;

        newRow.Value = vtqInfotableForProperty.value;

        newRow.Time = vtqInfotableForProperty.time;

        

        // Add the row to the infotable.

        result.AddRow(newRow);

    }

}


// Lastly, get the properties descriptions and perform an inner join on it against the result infotable.

// result: INFOTABLE dataShape: "PropertyDefinition"

var propertyDefinitions = me.GetPropertyDefinitions({

type: undefined /* STRING /</div><div>});</div><div><br></div><div>// Use the Intersect function to perform an inner join</div><div>// result: INFOTABLE</div><div>var result = Resources["InfoTableFunctions"].Intersect({</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>t2: propertyDefinitions / INFOTABLE /,</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>t1: result / INFOTABLE /,</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>joinColumns2: "name" / STRING /,</div><div>    joinColumns1: "Name" / STRING -- note, this is case sensitive, and my datashape has "Name" defined, not 'name' /,</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>columns2: "description" / STRING /,</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>columns1: "Name,Value,Time" / STRING /,</div><div><span class="Apple-tab-span" style="white-space: pre;"> </span>joinType: "INNER" / STRING */

});

////


Lastly, I can send an export of this script in a Thing if you want a working version.  Let me know.


Regards,

Riaan





jhemper
2-Explorer
(To:jhemper)

Thanks Riaan,

That was a great help, I think that I am starting to understand a little better now. I have added a further function to filter the result table before the inner join is performed and can display the required output in a grid. On the basis that the result table is dynamically created as the script runs, what is the best way to arrange the column order on a grid widget?

Regards

Jan



paic
12-Amethyst
(To:jhemper)

If you click on the Grid widget then from the drop down or from the wheel towards the middle left, you can go to the Configure Grid Columns Menu.

This menu then allows you to order and set visibility on the grid columns as well as their renderers.

riaanl
7-Bedrock
(To:jhemper)

Jan, 

I'm not sure I understand your question.  While the contents of the infotable is dynamically added, the columns are known, correct?  If so, just ensure that the service output has a datashape defined and you will be able to organize the column order within the mashup builder (as Pai just mentioned).


If you do not have the datashape defined in the service output, then you will not be able to manually order the columns in the mashup builder.  In other words, the mashup builder relies on the datashape definition for configuration.


Regards,

Riaan




jhemper
2-Explorer
(To:jhemper)

Sorry guys, let me try and be a little more clear:

The service output has a datashape defined, when in the configuration environment I can configure the column order and size, any changes made are reflected on the mashup when viewed in configuration. When I actually view the mashup in the runtime environment all formatting is lost and the columns seem to revert to default / random formatting.

Sorry for the confusion.

Thanks

Jan



riaanl
7-Bedrock
(To:jhemper)

Do you by chance have the 'ShowAllColumns' property checked on the grid widget?  If so, uncheck it.

Also, what Thingworx version are you using?

jhemper
2-Explorer
(To:jhemper)

Hi guys,

I did indeed have the 'ShowAllColumns' property checked, apologies for that.

Many thanks for your help.

Regards

Jan

Announcements


Top Tags