Optimizing Communication

Loupe UX incorporates several features to enhance communication between the server and client. These features are designed to function without any configuration, but can be fine-tuned to meet specific requirements.

Introduction

Loupe UX operates by scraping the DOM for any elements that require reading variables from the PLC, then polling the server for that data. By default, every variable will be read as fast as possible. This is a good starting point but can be tuned to your specific needs.

Because HMI elements generally use a single member of a PLC data structure, Loupe UX will only read the structure member that is used. This is done to reduce the amount of data that is read from the PLC. If you have a structure with 100 members but only use 1, Loupe UX will only read the 1 member. For example, if you have a structure called MyStructure with a member called MyMember, Loupe UX will only read MyStructure.MyMember. This is done by default and does not require any configuration.

If you are reading many items from a structure, or all items of a structure, it is usually much more efficient to read the entire structure using a single read call. It is very difficult to automatically decide which is more efficient in all cases, so it is up to the developer to do some optimizations as required.

Reading Structures

Reading structures can be done two ways:

  1. Manually add structures using machine.initCyclicRead():
// Given the following structure:
MyStructure: {
    substruct:{
        ... A bunch of members or substructures ...
    }
}

// Add the level of structures you want to read
machine.initCyclicRead("MyStructure.substruct");
  1. Add an element to the DOM that uses a member of the structure
<!-- This will read the entire structure -->
<div data-var-name="MyStructure.substruct"></div>

Regardless of the method used, the timing of the call does not matter. Children of a structure that were previously read will be removed, since the parent structure is already read.

Data Read Groups

As users navigate between pages in a single-page app, the number of variables read may accumulate. This can be addressed by employing Data Read Groups.

Data Read Groups enable the grouping of variables, allowing them to be read and written as a cohesive unit. This facilitates reading and writing different sets of variables on different pages, and at different frequencies.

For instance, you can create a Data Read Group for a page that deals with variables for a motor and another for a pump. These groups will be read according to their frequency and consolidated when it comes time to read and write the variables.

To add a Data Read Group, simply include the data-read-group attribute in a parent element:

<div data-read-group="anOuterSet">
  // All elements in this div will be in the "anOuterSet" read group
  <button data-var-name="MyStructure.substruct.x"></button>
  <div data-read-group="anInnerSet">
    //All the elements in this div will be in the "anInnerSet" read group
    <button data-var-name="MyStructure.substruct.y"></button>
  </div>
</div>

Each element adds the variables it requires to the closest parent data-read-group element. If there is no parent data-read-group, the variables are added to the default group named global.

Data Read Group API

machine.initCyclicRead(varName: string): void

Parameter Description
varName The variable name to be cyclically read.

machine.initCyclicReadGroup(groupName: string, varName: string): void

Parameter Description
groupName The name of the Data Read Group to which the variable will be added.
varName The variable name to be added for cyclic reading within the specified group.

machine.setReadGroupMaxFrequency(groupName: string, maxFrequency: number): void

Parameter Description
groupName The name of the Data Read Group for which the maximum frequency is set.
maxFrequency The maximum frequency (in Hz) for cyclic reading within the specified group.

machine.setReadGroupEnableCallback(groupName: string, callback: (group: ReadGroup, wouldShow: boolean) => boolean): void

Parameter Description
groupName The name of the Data Read Group for which the callback is set.
callback A function that determines if the read group should be enabled.

machine.setReadEnableCallback(callback: (group: ReadGroup, wouldShow: boolean) => boolean): void

Parameter Description
callback A global function that determines if the read group should be enabled.

machine.getReadGroup(groupName: string): ReadGroup | undefined

Parameter Description
groupName The name of the Data Read Group to retrieve.

machine.getReadGroupList(): ReadGroup[]

Parameter Description
None Returns a list of all Data Read Groups.

machine.printReadGroups(): void

Parameter Description
None Prints all Data Read Groups to the console for debugging.

Example Usage

// Add a variable to the default read group
machine.initCyclicRead("MyVar.in.command");

// Add a variable to a specific read group
machine.initCyclicReadGroup("anOuterSet", "Page:MyVar.in.command");

// Set the max frequency (in Hz) of a read groups
machine.setReadGroupMaxFrequency("anOuterSet", 2);

// Use a function to determine if a read group should be enabled
// This allows the user to change the behavior of when the read group is enabled
// Return true for automatic behavior, false to manually enable/disable
function anOuterSetShouldEnable(group, wouldShow) {
  group.enable = wouldShow;
  return false; // Return false to manually enable/disable
}
machine.setReadGroupEnableCallback("anOuterSet", anOuterSetShouldEnable);

// Set the global callback function
// This will be called for all read groups that do not have a specific callback or that return false from their callback
machine.setReadEnableCallback((group, wouldShow) => {
  // Do something with the group
  // Return true to fallback to automatic behavior, or false if you manage the enable/disable yourself
  return true;
});

// Get a specific read group by name
machine.getReadGroup("CommsLowFrequency");

// Get all read groups
machine.getReadGroupList();

// Print all read groups to the console for debugging
machine.printReadGroups();