Preview historical logs using Export Block Descriptors in viewON

This is the third example in a series of posts about using Export Block Descriptors in viewON projects. To view the other examples as well as helpful resources, return to the main post.

Example 3 - Historical Log Preview

image
In this final example, we’ll use a third-party library to view a sample of historical data before we download the result. In this case, we’re using Papa Parse, a JavaScript library that provides tools for parsing CSV files into JavaScript objects so that we can display the data being requested in a convenient format, allowing the user to adjust the parameters of their request before downloading the data they want.

image

Unlike in the previous examples, we’ll need code that runs before the user presses any buttons here.

  1. Go to the actions tab with no elements selected
  2. Add a new JavaScript Section and reduce the interval to 0 so that it doesn’t repeat – otherwise, the code will execute every N milliseconds, and we just want to load the library once
  3. We’ll use a JQuery function to load the script here. The function() { … part after the script’s address can be ignored; it’s a callback function which is triggered after the script loads, and it’s just used to log that the script loaded successfully.

Next, we can begin begin adding code to the button used to display the historical log sample:

//Construct the query by starting with the static bit, then adding details
var query = "$dtHL$ftT";
var hoursPrior = $("#UID_1645221093029").val();
if (Number.isInteger(parseInt(hoursPrior))) query+= "$st_h" + hoursPrior;

//The argument for tag groups is just a series of letters, like ACD,
//so we can just add a letter to an empty string for each checked box
//and then check if the string is no longer empty
var groups = "";
if ($("#UID_1645225336852").prop("checked")) groups+= "A";
if ($("#UID_1645225345236").prop("checked")) groups+= "B";
if ($("#UID_1645225345071").prop("checked")) groups+= "C";
if ($("#UID_1645225345478").prop("checked")) groups+= "D";
if (groups != "") query+= "$fl" + groups;

Just like in the first two examples, here we construct the EBD by checking the values of the elements we’re using for user input. A small twist is that check boxes don’t store whether they’re checked in their value attribute, they store it in a property called “checked”. The value of properties can be accessed with .prop(“propertyName”), which in this case returns either true or false. We use this in a series of if statements, starting with an empty string and adding the letters for tag groups. Finally, we check if the string is still empty. If it’s not, we know that at least one tag group is checked, so we add the tag group parameter to the EBD.

//Begin parsing the file. File parsing is asynchronous, so use the complete callback
//to tell it what to do once parsing is complete
//This first parse grabs the taglist since the historical log only includes tag IDs
Papa.parse("http://192.168.120.53/rcgi.bin/ParamForm?AST_Param=$dtTL$ftT", {
     download: true,
     header: true,
     complete: function(results) {
          var tagNames = {};
          results.data.forEach(function(item) {
               tagNames[item.Id] = item.Name;
          });
          console.log("Tag names loaded");
          loadHL(tagNames);
     }
});

The next chunk of code sends an EBD request to the Ewon for a list of tags. In the first part of this example, when we loaded Papa Parse, we mentioned a callback function but said it could be ignored as it was just logging that Papa Parse was loaded. Here, it’s important to use one. Callback functions are triggered after some state is reached, in this case after Papa Parse finishes parsing the data from the Ewon, so that further actions don’t take place prematurely. When Papa finishes parsing the resulting CSV:

  • Create an empty object called tagNames
  • For each tag in the results, create a pairing between its ID and its name in tagNames
    • Now if we have an ID and want the tag’s name, we just use tagName[tagID] to find it
  • With this done, we call the function loadHL, passing tagNames to it, which performs a second request to retrieve the data specified by the user
//This function is used for parsing the actual historical log, and its callback
//function uses the previously parsed tag list to replace tag IDs with tag names
//Finally, it calls displaySample() 
function loadHL(tagNames) {
     console.log(query);
     Papa.parse("http://192.168.120.53/rcgi.bin/ParamForm?AST_Param=" + query, {
          download: true,
          header: true,
          complete: function(results) {
               var histLog = results.data.map(function(item) {
                    return {name: tagNames[item.TagId], time: item.TimeStr, value: item.Value};
               });
               console.log("Historical log loaded");
               displaySample(histLog);
          }
     });
}

This time within the callback function, we use the function yourArray.map(function(item) { … }) to create a new array from the results of applying a function to each element of the first array. In this case, we take the array of historical log entries from Papa Parse, and for each item return an object containing the name (obtained using tagNames and the item’s tag ID), the formatted time, and the item’s value. The result is a new array called histLog containing just those three bits of data for every single row in the historical log. Finally, we pass that to displaySample to see our preview.

//Provided with an array of tag data objects, it empties the list element and
//fills it with up to 10 sample rows of data, 5 from the start and 5 from the end
function displaySample(histLog) {
     var sampleText = [];
     var formatHLRow = function(item) {return item.time + ": " + item.name + " = " + item.value;};
     if (histLog.length > 10) {
          var first5 = histLog.slice(0, 5).map(formatHLRow);
          var last5 = histLog.slice(histLog.length-6, histLog.length-1).map(formatHLRow);
          sampleText = [].concat(first5, ["..."], last5);
     } else {
          histLog.forEach(formatHLRow);          
     }

     $("#UID_1645809877086").empty();
     sampleText.forEach(function(text) {
          $("#UID_1645809877086").append($('<option></option>').text(text));
     });
}

To display our data, we just want an array of strings containing the time, tag name, and tag value. We can do this by defining a formatting function and using map:

  • Start with an empty array to which we will add our strings
  • Define a function that takes in a histLog item and returns a string with its time, name, and value
  • If there are more than 10 entries in histLog, use slice to create new arrays containing the first five and last five, then use map to format them with formatHLRow
    • In between the first five and last five, add an element containing just an ellipsis
    • [].concat(arr1, arr2, arr3) starts with an empty array and makes a new array with all the elements of arr1, arr2, and arr3 in the same order as in their original arrays
  • If there are less than 10 entries, we just display them all
  • Use .empty() to empty the list element of any entries it might have from previous samples
  • Finally, add an option element for each row of sample data

All that’s left in this example is adding a download button for when the user is satisfied with the sample data they’ve retrieved. After adding the button itself and then adding a JavaScript action to go with it, we can use the following code to download the requested data:

//Construct the query by starting with the static bit, then adding details
var query = "$dtHL$ftT";
var hoursPrior = $("#UID_1645221093029").val();
if (Number.isInteger(parseInt(hoursPrior))) query+= "$st_h" + hoursPrior;

//The argument for tag groups is just a series of letters, like ACD,
//so we can just a letter to an empty string for each checked box
//and then check if the string is no longer empty
var groups = "";
if ($("#UID_1645225336852").prop("checked")) groups+= "A";
if ($("#UID_1645225345236").prop("checked")) groups+= "B";
if ($("#UID_1645225345071").prop("checked")) groups+= "C";
if ($("#UID_1645225345478").prop("checked")) groups+= "D";
if (groups != "") query+= "$fl" + groups;

var url = "http://192.168.120.53/rcgi.bin/ParamForm?AST_Param=" + query;
window.open(url, "download");