JavaScript (basic to advance) for TwinCAT HMI

JavaScript Function:

A JavaScript function is a block of code designed to perform a particular task. A JavaScript function is executed when “something” invokes it (calls it). An example of a JavaScript function :

let hello = function() {
  return "Hello World!";
}

We just call the method in the following way:

console.log(hello ());  //it will print Hello World! in the console

JavaScript function with Parameters:

let hello = function(st1, st2) {
  return "Hello World!" + st1 + st2;

}

When we call the above method, it will print Hello World! for TwinCAT HMI

console.log(hello(' for', ' TwinCAT HMI')); //it will print Hello World! for TwinCAT HMI in the console

 JavaScript Arrow function:

The above function can be shortened by using the arrow function in the following way with the same output.

let hello = (st1, st2) => {
  return "Hello World!" + st1 + st2;
}
console.log(hello(' for', ' TwinCAT HMI')); //same output as before

All the above functions are synchronous JavaScript functions. All these functions are executed in sequence. If a function call takes a long time then UI will be irresponsive. We can insert the following code in the HMI JavaScript editor and test it.

 

Figure 1: Usages of JavaScript function in TwinCAT environment

When we use JavaScript in the TwinCAT environment, we can see the console output in the following way.

=> Press on the live view

=> Press on the gear icon

=> Press on the console tab, now we can see the output of our program (if we have used the console.log function)

Note: If we use the browser for example Chrome (press F12) or find the developers tool in the browser menu

Figure 2: Shows how to display the console out with the TwinCAT tools (F12 or developer tools with Chrome)

Anonymous functions:

In JavaScript, anonymous functions (function expression) are those that are produced without a name or identifier to refer to them; they are defined as :

 myfunc = (function () {  // there is no name between function and ()
   console.log('inside anonymous function');
});
myfunc();  // output inside anonymous function

Named functions:

Normal functions (function declaration) having a name or identifier to refer to them are referred to as named functions and are defined as:

function displayMessage(){
console.log('inside normalfunction');
}
displayMessage();

Self calling functions:

Function expressions can be made “self-invoking”. A self-invoking expression is invoked (started) automatically, without being called. Function expressions will execute automatically if the expression is followed by (). You cannot self-invoke a function declaration. You have to add parentheses around the function to indicate that it is a function expression:

(function () {
  let x = "Hello!!";  // I will invoke myself
  console.log('Ha ha calling myself');
})();

Using anonymous functions as arguments:

In practice, you often pass anonymous functions as arguments to other functions. For example:

setTimeout(function() {
    console.log('Execute later after 1 second')
}, 1000);

setTimeout takes 2 parameters, first one a anonymous function and second one is the timeout value.

In this example, we pass an anonymous function into the setTimeout() function. The setTimeout() function executes this anonymous function one second later.

Asynchronous JavaScript function:

In real life, things happen asynchronously. For example, when we ask for web pages from a server, it may take some time. The web engine will call or notify the browser by an event. An event handler is a particular type of callback. A callback is just a function that’s passed into another function, with the expectation that the callback will be called at the appropriate time.

An example of an asynchronous function:

setTimeout(function() {
  myFunction("I love TwinCAT HMI!");
},
3000);
function myFunction(value) {
  console.log(value); //output in the console, I love TwinCAT HMI!
}

 

Some server calls (getting data from the HMI Server or the PLC ) examples:

Reading data from the PLC may be successful or it may fail. In either case, it will be called sometimes later. If we want to use the result or if we want to handle the error we have to put our code in the appropriate places. If we have a few similar calls then it will be messy. So we try to synchronize the call as we are calling synchronous function. More has been described at https://infosys.beckhoff.com/english.php?content=../content/1033/te2000_tc3_hmi_engineering/4702049035.html&id=

var symbol = new TcHmi.Symbol('%s%PLC1.MAIN.EmptyArray%/s%');
symbol.readEx(function(data) {
  if (data.error === TcHmi.Errors.NONE) {
    var value1 = data.value;
    var myJSONString1 = JSON.stringify(value1);
    //Success, do something with value1
  } else {
    console.log('ReadEx error');
    //Error, handle it
  }
});

 

The following code uses a Promise object which takes a function as a parameter. The parameter function takes two arguments, the resolve and reject function. When a function was called successfully then it will call resolve and in the error case, it will call reject after 3 seconds.

let completed = true; // set true or false to test
let learnTC = new Promise(function (resolve, reject) {
    setTimeout(() => {
        if (completed) {
            resolve("I have learned TwinCAT HMI");
        } else {
            reject("I haven't learned TwinCAT HMI");
        }
    }, 3 * 1000);
});
learnTC .then((value) => {
  console.log(value);
  // expected output: I have learned TwinCAT HMI.
}).catch((err) => {
  console.log(err);
  // expected output: I haven't learned TwinCAT HMI.
});

 

Lets modify the code a bit, when we have call a function from server it can be OK (gotData is true) or it can fails (gotData is false). The result what has been push by resolve or reject call will be available in the caller.

let gotData = false;
function resolveORRejectAfter5Seconds() {
  return new Promise((resolve, reject) =>{
    setTimeout(() =>{
      if (gotData) {
        resolve('resolved');
      } else {
        resolve('rejected');
      }
    },
    5000);
  });
}
async
function asyncCall() {
  console.log('calling');
  const result = await resolveORRejectAfter5Seconds();
  console.log(result);
  // expected output: "resolved" or "rejected" after 5 seconds based on value of gotData
}
asyncCall();

 

Asynchronous call as synchronous:

Create a code behind the JavaScript file. We add two functions, one for reading and another for writing data to the PLC using promise. Note that when there is no error then we call resolve and when there is an error we call reject and pass a custom JavaScript object. See errorData object.

function ReadPLCVariable(symbolString) {
    return new Promise((resolve, reject) => {
        var symbol = new TcHmi.Symbol(symbolString);
        symbol.readEx(function (data) {
            if (data.error === TcHmi.Errors.NONE) {
                resolve(data.value);
            } else {
            const errorData = {
                ErrorCode: data.error,
                ErrorText: `Error in ReadPLCVariable symbolString = ${symbolString}`
                };
                reject(errorData);
            }
        });
    });
}
function WritePLCVariable(symbolParameter, dataParameter) {
    return new Promise((resolve, reject) => {
        TcHmi.Symbol.writeEx(symbolParameter, dataParameter, function (data) {
            if (data.error === TcHmi.Errors.NONE) {
                resolve(data.error);
            } else {
            const errorData = {
                ErrorCode: data.error,
                ErrorText: `Error in WritePLCVariable, symbolParameter = ${symbolParameter}`
                };
                reject(errorData);
            }
        });
    });
}

We shall use those functions from an action and condition editor that is from an embedded JavaScript code.

async function asyncFunctionCall() {
try {     const doorAtHome = await ReadPLCVariable('%s%PLC1.MAIN.doorAtHome%/s%');     const motorStatus = await ReadPLCVariable('%s%PLC1.MAIN.motorStatus%/s%');     if(doorAtHome == true && motorStatus == true){     await WritePLCVariable('%s%PLC1.MAIN.motorOutPut%/s%', true);     } }
catch(error) {     console.log(`ErrorCode = ${error.ErrorCode}`);     console.log(`ErrorText = ${error.ErrorText}`);   } } asyncFunctionCall();

If all are OK then motorOutPut will be written to true and there will be no console output. But if we make some mistake for example we write mistake doorAtHome to doorAtHome1  then we get the following error code in the console window.

ErrorCode = 3005
ErrorText = Error in ReadPLCVariable symbolString = %s%PLC1.MAIN.doorAtHome1%/s%

So we know when and what error occurred with much nicer code! 

In this way, we can avoid the Callback Hell see more at http://callbackhell.com/

Download the test sample TcHmiJSBasicPromise.zip

Asynchronous function to synchronous

Call asynchronous function inside TwinCAT function.

See the following code, we have our function and we are calling an async function

            function ShowErrorToUI(Data, Message) {
                console.log(`Data point #1`);
                var BoolData = undefined;
                let myParameterData = false;
                async function asyncMyCall() {
                    try {
                        myParameterData = await ReadPLCVariable('%s%PLC1.MAIN.doorAtHome%/s%');
                        console.log(`myParameterData = ${myParameterData}`);                      
                        BoolData = await ReadPLCVariable('%s%PLC1.MAIN.motorStatus%/s%');
                        console.log(`BoolData = ${BoolData}`);                        
                        console.log(`Data point #2`);
                    }
                    catch (error) {
                        console.log(`error occured = $ {error}`);
                    }
                    console.log(`Data point #3`);
                }
                console.log(`Data point #4`);
                asyncMyCall();
                console.log(`Data point #5`);
            }

The output of the above function

Data point #1
Data point #4
Data point #5
myParameterData = true
BoolData = true
Data point #2
Data point #3

The point I see is that if we want to use manipulated variable by the async function we have to be careful when to use those variables. 

Lets see the following example.

var result = 0;
function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(20);
    }, 2000);
  });
}
async function asyncCall() {
  console.log('calling');
  const result = await resolveAfter2Seconds();
  console.log('result =' + result);
  return result;
}
var v = asyncCall();
console.log(v);

Output:

"calling"
[object Promise] { ... }
"result =20"

asyncCall print the calling and then return the promise object and finally the result is printed.

More about asynchronous function

undefined or 'undefined'

What are the differences between undefined and ‘undefined’ in JavaScript?

undefined is a primitive value automatically assigned to variables that have just been declared, or to formal arguments for which there are no actual arguments.

‘undefined’ is a string

var a = 'undefined';
if(a == 'undefined') {
console.log('a is undefined');  // a is undefined
}
var a ;
if(a == 'undefined') {
console.log('a is undefined');  // no output as a is not equal to string 'undefined'
}
var a ;
if(a == undefined) {
console.log('a is undefined'); // a is undefined
}

var, let and const

var english = "Hello there!";
let french = "Bonjour!";
const german = "Hallo!";

 

var:

var is function scoped when it is declared within a function. This means that it is available and can be accessed only within that function.

var tester = "hey hi";
function newFunction() {
  var hello = "hello";
}
console.log(hello); 
//Error in browser console
Reason: An uncaught exception occurred in the processing of a JavaScript action
Exception: ReferenceError: hello is not defined
Domain: TcHmi.System.TriggerManager 

 

Declare and redeclare variable with var:

var greeter = "hey hi";
var greeter = "say Hello instead";
 
var greeter = "hey hi";
greeter = "say Hello instead"; 

 

Let:

let is now preferred for variable declaration. It’s no surprise as it comes as an improvement to var declarations.

let is block scoped

 

A block is a chunk of code bounded by {}. A block lives in curly braces. Anything within curly braces is a block.

let can be updated but not re-declared.

Just like var,  a variable declared with let can be updated within its scope. Unlike var, a let variable cannot be re-declared within its scope. So while this will work: 

let greeting = "say Hi";
greeting = "say Hello instead";  

Following statement will return an error: 

let greeting = "say Hi";
let greeting = "say Hello instead"; 
// error: Identifier 'greeting' has already been declared
 

However, if the same variable is defined in different scopes, there will be no error:

 let greeting = "say Hi";
 if (true) {
    let greeting = "say Hello instead";
    console.log(greeting); // "say Hello instead"
 }
console.log(greeting); // "say Hi"

 

 

Const

Variables declared with the const maintain constant values. const declarations share some similarities with let declarations.

 

const declarations are block scoped

Like let declarations, const declarations can only be accessed within the block they were declared.

 

const cannot be updated or re-declared

This means that the value of a variable declared with const remains the same within its scope. It cannot be updated or re-declared. So if we declare a variable with const, we can neither do this:

const greeting = "say Hi";
greeting = "say Hello instead";// error: Assignment to constant variable. 

The following will cause the error as well

const greeting = "say Hi";
const greeting = "say Hello instead";// error: Identifier 'greeting' has already been declared

Every const declaration, therefore, must be initialized at the time of declaration.

This behavior is somehow different when it comes to objects declared with const. While a const object cannot be updated, the properties of this objects can be updated. Therefore, if we declare a const object as this:

const greeting = {
message: "say Hi",
    times: 4
}

while we cannot do this:

 
greeting = {
words: "Hello",
    number: "five"
} // error:  Assignment to constant variable.

we can do this:

greeting.message = "say Hello instead";

This will update the value of greeting.message without returning errors.

 

 

JavaScript Object

JavaScript Primitive type:

string
number
boolean
null
undefined
symbol
bigint

 

A JavaScript object is a collection of named values

It is a common practice to declare objects with the const keyword.

const person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};
console(person.firstName + " " + person.lastName); //print John Doe

 

We can write the above code by formatting it in the following way.

var person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
 // returns 50
console.log(person ['age'] ); // 50
console.log(person ['eyeColor'] ); //blue
person.hasAddress = false;  //new property
delete person.eyeColor;  //delete eyeColor property
console.log(person ['eyeColor'] );  //undefined
console.log(person ['hasAddress'] );  //false
for (var key in person){
  console.log(key); // logs keys in person
  console.log(person[key]); // logs values in person
}

 

We can access object property by dot notation or bracket notation. 

 

 We have an object person, we get his name from the UI and he owns several cars, how do we make JSON string for this.

How to pass JavaScript Object to extension with array

const cars = ["Saab", "Volvo", "BMW", "AnotherOne", "Something"];
var vals=[];
for(var i=0;i<cars.length;i++){
   vals.push(cars[i]);
}  
     const person = {
        Name: 'John',
        Age: 25,
        Married: false,
        Cars : vals
    };  
var myJsonString = JSON.stringify(person);
const myobjectBack = JSON.parse(myJsonString);
console.log(myobjectBack);

The output will be :

Object
Age: 25
Cars: (5) ["Saab", "Volvo", "BMW", "AnotherOne", "Something"]
Married: false
Name: "John"
__proto__: Object

And if we pass the data to extension, we can find the value of 

TcHmi.Symbol.writeEx('%s%ServerExtensionCSharpEmpty1.WriteValueAdd%/s%', myJsonString,
function(data) {
  if (data.error === TcHmi.Errors.NONE) {
    console.log('Write OK');
  } else {
    console.log('Write NOT OK');
  }
});
command.WriteValue = {"Name":"John","Age":25,"Married":false,"Cars":["Saab","Volvo","BMW","AnotherOne","Something"]}

 

Complex JavaScript Object

var globalArray = [];
var globalObjects = {};
var globalStrokeColor = '#00ff00';
globalObjects['objectID_1'] = {
coordinates: [{
lat: 65.71988818952737,
lng: 26.859262689448833
},
{
lat: 65.72081178499442,
lng: 26.857662854998747
}
],
strokeColor: globalStrokeColor,
faulty: false,
name: "objectID_1"
};
for (var singleObject in globalObjects) {
console.log(globalObjects[singleObject].coordinates[0].lat);  // lat value from inner object
console.log(globalObjects[singleObject].faulty); //faulty property
console.log(globalObjects[singleObject].name); //name property
}

JavaScript typeof

In JavaScript there are 5 different data types that can contain values:

string
number
boolean
object
function

There are 6 types of objects:

Object
Date
Array
String
Number
Boolean

And 2 data types that cannot contain values:

null
undefined
typeof "John"                 // Returns "string"
typeof 3.14                   // Returns "number"
typeof NaN                    // Returns "number"
typeof false                  // Returns "boolean"
typeof [1,2,3,4]              // Returns "object"
typeof {name:'John', age:34}  // Returns "object"
typeof new Date()             // Returns "object"
typeof function () {}         // Returns "function"
typeof myCar                  // Returns "undefined" *
typeof null                   // Returns "object"

JavaScript Array function

concat()    Joins arrays and returns an array with the joined arrays

constructor Returns the function that created the Array object’s prototype

copyWithin() Copies array elements within the array, to and from specified positions

entries()   Returns a key/value pair Array Iteration Object

every() Checks if every element in an array pass a test

fill()    Fill the elements in an array with a static value

filter() Creates a new array with every element in an array that pass a test

find() Returns the value of the first element in an array that pass a test

findIndex() Returns the index of the first element in an array that pass a test

forEach() Calls a function for each array element

from() Creates an array from an object

includes() Check if an array contains the specified element

indexOf() Search the array for an element and returns its position

isArray() Checks whether an object is an array

join() Joins all elements of an array into a string

keys() Returns a Array Iteration Object, containing the keys of the original array

lastIndexOf() Search the array for an element, starting at the end, and returns its position

length Sets or returns the number of elements in an array

map() Creates a new array with the result of calling a function for each array element

pop() Removes the last element of an array, and returns that element

prototype Allows you to add properties and methods to an Array object

push() Adds new elements to the end of an array, and returns the new length

reduce() Reduce the values of an array to a single value (going left-to-right)

reduceRight() Reduce the values of an array to a single value (going right-to-left)

reverse() Reverses the order of the elements in an array

shift() Removes the first element of an array, and returns that element

slice() Selects a part of an array, and returns the new array

some() Checks if any of the elements in an array pass a test

sort() Sorts the elements of an array

splice() Adds/Removes elements from an array

toString() Converts an array to a string, and returns the result

unshift() Adds new elements to the beginning of an array, and returns the new length

valueOf() Returns the primitive value of an array

Maps

A Map holds key-value pairs where the keys can be any datatype. A Map remembers the original insertion order of the keys. A Map has a property that represents the size of the map.

const fruits = new Map([
  ["apples", 500],
  ["bananas", 300],
  ["oranges", 200]
]);
console.log(fruits.get("apples")); // 500

JSON

Basic JSON rules:

=>JSON is text, and we can convert any JavaScript object into JSON, and send JSON to the server.

=>Data is in name/value pairs

=>Data is separated by commas

=>Curly braces hold objects

 

=>Square brackets hold arrays

JSON data is written as name/value pairs.

Understanding JSON Schema: https://json-schema.org/understanding-json-schema/index.html

A name/value pair consists of a field name (in double quotes), followed by a colon, followed by a value:

JSON Example:

{"name":"John"}

 A common use of JSON is to exchange data to/from a web server. When sending data to a web server, the data has to be a string. Convert a JavaScript object into a string with JSON.stringify().

const obj = {name: "John", age: 30, city: "New York"};

 

JSON.stringify() 

Use the JavaScript function JSON.stringify() to convert it into a string. An object is converted to string before transferring to server or vice versa.

const myJSON = JSON.stringify(obj);
console.log(myJSON);  //output {"name":"John","age":30,"city":"New York"}

 

JSON.parse() 

JSON is converted to object and then we do analysis with the object.

let anotherObject = JSON.parse(myJSON);
var combobox = TcHmi.Controls.get("TcHmiNameBox");
combobox .setText(anotherObject.name);
console.log(`anotherObject.name = ${anotherObject.name}`);

anotherObject  and obj has the same fields and value.

Convert an JSON to string by https://tools.knowledgewalls.com/json-to-string

 

var vals = [];
const myData = {
  CurrentTime: 'current time',
  Test1: 'A anme',
  Test2: "2nd str"
};
vals.push(myData);
let valsString = JSON.stringify(vals);
let myDataString = JSON.stringify(myData);
console.log(valsString);
console.log(myDataString);
let anObjectArray = JSON.parse(valsString);
let anObject = JSON.parse(myDataString);
console.log(anObjectArray[0].CurrentTime);
console.log(anObjectArray[0].Test2);
console.log(anObject.Test2);

Output of the above program, note that when we convert array to string that start with ‘[‘. String is used for transferring between client and server. Object is handy to use for example  for updating a control,

myControl.setText(anObject.Test2);

//Output

 '[{"CurrentTime":"current time","Test1":"A anme","Test2":"2nd str"}]'
 '{"CurrentTime":"current time","Test1":"A anme","Test2":"2nd str"}'
 "current time"
 "2nd str"
 "2nd str"

 

Reading JSON Array Data from PLC

We have an array of objects which has been declared in PLC

AS JSON:

 {
  "Test1": "100",
  "Test2": 1
 }

The symbol in PLC can be :

 

Reading an Item at any index :

Reading the first array entry , it will get as an Object of type JSON

data.value will be the JSON object with 2 fields Test1 and Test2.

"%s%PLC1.MAIN.myArray_HMI[0]%/s%"
Reading all data %s%PLC1.MAIN.myArray_HMI%/s%

Reading all data at a time from PLC:

TcHmi.Symbol.readEx2('%s%PLC1.MAIN.myArray_HMI%/s%', function (data){

data.value is as array of object of type JSON object, how many entry we have,  data.value.length will give it.

 

Writing single object to a particular index in PLC:

Both JSON string and object works when we update an element of an array. We can pass the data as object or JSON string. The result is same which is indicated by myJSONString/myObject in the following code.

var myJSONString = JSON.stringify(myObject);
TcHmi.Symbol.writeEx('%s%PLC1.MAIN.myArray_HMI[0]%/s%',  myJSONString/myObject, function (data) {
 

 

Writing all objects to PLC:

Full array can be saved as array of objects or convert array to JSON then pass the data to writeEx as shown in the following code.

TcHmi.Symbol.writeEx('%s%PLC1.MAIN.myArray_HMI%/s%', asArray);
TcHmi.Symbol.writeEx('%s%PLC1.MAIN.myArray_HMI%/s%', JSON.stringify(asArray));

 

JSON Schema

Tips

01: SyntaxError: Unexpected token o in the JSON at position 1

const cars = ["Saab", "Volvo", "BMW"];
let myvar = JSON.parse(cars);

The JSON.parse() method parses a string and returns a JavaScript object, but we are trying to parse an array of string.

02: An error occurred when we use to parse array

The JSON.parse() method parses a string and returns a JavaScript object, but we are trying to parse an array

03: 

 An uncaught exception occurred in the processing of a JavaScript action

 Exception: SyntaxError: Unexpected identifier

04: 

Right way to use the JSON and array

05:  Declare variable in right place when we write the code to avoid surprise such as variables are not updated properly.

Lets see the following code:

const cars = ["Saab", "Volvo", "BMW", "SKODA", "OPEL"];
var vals = [];
var newObject = {
carname: '',
id: 0
};
for (var i = 0; i < cars.length; i++) {
if (cars[i] != undefined && cars[i].length > 0)
newObject.carname = cars[i];
newObject.id = i + 1;
vals.push(newObject);
}
let myString = JSON.stringify(vals);
console.log(`myString = ${myString}`);

 //output as follows and we see carname is OPEL and id is 5

myString = [{“carname”:”OPEL”,”id”:5},{“carname”:”OPEL”,”id”:5},{“carname”:”OPEL”,”id”:5},{“carname”:”OPEL”,”id”:5},{“carname”:”OPEL”,”id”:5}]

 

Solution to this problem is we declare in the following way:

const cars = ["Saab", "Volvo", "BMW", "SKODA", "OPEL"];
var vals = [];
for (var i = 0; i < cars.length; i++) {
  var newObject = {
carname: '',
id: 0
};  
if (cars[i] != undefined && cars[i].length > 0)
newObject.carname = cars[i];
newObject.id = i + 1;
vals.push(newObject);
}
let myString = JSON.stringify(vals);
console.log(`myString = ${myString}`); // This will give the correct output

06: 

When we call an asynchronous function call from the TwinCAT HMI framework then the result comes by callback. In the following image we see that when we tried to read data we got an error.

data.details.code = 3005 when has been described in the page https://infosys.beckhoff.com/english.php?content=../content/1033/te2000_tc3_hmi_engineering/3758305291.html&id=

The reason is data.details.errors[0].reason.

07: 

When  we use JSON.perse() and when stringfy()

Normally when we project data inside our software then it is better to have objects. When we transfer data to remote server then we transfer as string.

When data arrives to our software we need to use JSON.perse()  to get objects and before transferring data we use stringfy(). We can’t transfer objects but string. Consult or check if the API provides  string or object.

 

By the following sample, we are converting myObject to JSON string then writing to writeEx method.

var myJSONString = JSON.stringify(myObject);
TcHmi.Symbol.writeEx('%s%ServerExtensionCSharpEmpty1.WriteValueAdd%/s%', myJSONString, function (data) {

Following example, expect that data3 will arrive as string and then we can convert to object for processing.

TcHmi.Symbol.readEx2('%s%PLC1.MAIN.collectionGroups_HMI%/s%', function (data3) {
if (data3.error === TcHmi.Errors.NONE) {

 

PLC variable is not seen in HMI though it has been mapped OK

08: 

When  we change the data in the PLC program then we need to map these again. Some data mapping goes wrong and the variables are not seen properly. For example, we have a small program as shown below:

//we have an array with index 0 and and last index 3, having 4 elements
PROGRAM MAIN
VAR
myArray_HMI : ARRAY [0..MAX_AMOUNT_INDEX] OF MyArray_struct; 
END_VAR
VAR CONSTANT
MAX_AMOUNT_INDEX: INT := 3;
END_VAR
//Now we redeclare the array  to 10,
so for HMI will have an mismatch and HMI will not able to read these. 
MAX_AMOUNT_INDEX : INT := 10;

Solution: We should check the mapped variables and remapped those, done!

 

09:  

Type mismatch (3005), Invalid type at ´DataField´ : ´Expected string, got int.

The error occurs when we have a type mismatch. For example, we have the following data in PLC.

TYPE MyData_struct :
STRUCT
ComboBox : INT;
END_STRUCT
END_TYPE
//In JavaScript, 
     const myObject = {
        ComboBox : ´
    };    
var myJSONString = JSON.stringify(myObject);
TcHmi.Symbol.writeEx('%s%PLC1.MAIN.myArray_HMI%/s%', myJSONString, function (data) {
    if (data.error === TcHmi.Errors.NONE) {
        // Handle success... 
    } else {
        //We got an error 3005
    }
});

The following error code is shown when code is 3005 (type mismatch and Range mismatch in the Array)

 

10:  JavaScript – Cannot set property of undefined.

The error occurs when we have a type mismatch. By mistake we are treating myObject as an array though we should use myNewArray .

https://stackoverflow.com/questions/7479520/javascript-cannot-set-property-of-undefined

Let’s show the occurrence by an example.

var myNewArray = [];
const myObject = {
myDay : 0,
myName : ' John'
};
for(var i = 0; i < 10; i++) {
myObject [l].myDay  = anotherArray[l].myDay; //Causes Cannot set property of undefined.
myObject [l].myName = anotherArray[l].myName;//Causes Cannot set property of undefined.
}

 

11:  JavaScript – Resolve calls OK but the catch block is executed (the error is undefined)

This happens, in that case, if we have done a mistake after calling the promise function, the following function will generate such an error.

async function asyncFunctionCall() {
try {
    var all = await ReadPLCVariable('%s%PLC1.MAIN.ArrayGate%/s%');
    cosole.log(all);  //<= this can cause such, it should be console but we have written cosole.log
    } catch(errorObject) {
    console.log(`ErrorCode = ${errorObject.ErrorCode}`);
    console.log(`ErrorText = ${errorObject.ErrorText}`);
  }    
}
asyncFunctionCall();

 

 

References:

Download the sample from the link given above.

See next how to use JavaScript at https://www.hemelix.com/scada-hmi/twincat-hmi/twincat-javascript-function-and-code-behind/

Ask questions related to Hemelix sample code and design at Google group https://groups.google.com/g/hemelix