TwinCAT HMI Symbol Data and Binding
(Video tutorial at the end)

In TwinCAT HMI a variable is called a symbol, in another system, it may be called tag as well. This symbol can be mapped or linked to the PLC variable. Some symbols can be local to the HMI server. That means it is not read from PLC. HMI server’s responsibility to keep up to date all the symbol which have been mapped.

Mapping is the event of telling the HMI Server where the needed symbols are located in the PLC.

A binding links any symbol to a property of a control. A binding automatically updates the property of the control when the value of the symbol changes. There are two types of binding:

=>Data binding, also called variable binding, a variable is linked to any property of a control then we say variable is bound to the property (see the image below).

=>Function binding, basically it means we can use a function for the control property.


Anatomy of binding:


TcHmi.Binding.createEx =>Creates a binding between a symbol and a control attribute using the attribute setter function, takes 3 parameters

Symbol expression (for example, HMI internal variable,  ‘%i%MyInternalSymbol_1%/i%’,  Server variable  ‘%s%PLC1.MAIN.varIntPlcVariable%/s%’, parameter variable %pp%someRealParameter%/pp%)

Name of the control setter function (for example, setText, setLeft  etc setter function for control properties)

Reference to the control instance (  for example,  var myControl = TcHmi.Controls.get(‘TcHmiTextbox_1’);)       

var myControl = TcHmi.Controls.get('TcHmiTextbox_1');
TcHmi.Binding.createEx('%i%MyInternalSymbol_1%/i%', 'setText', myControl);

CreateEx does not return anything if we want to sure may be a good idea to check by the following way:

var result = TcHmi.Binding.exists('Text',TcHmiTextbox_1);
console.log('Binding does exists');
} else {
console.log('Binding does not exists');

TcHmi.Binding.exists => Test if there is existing binding between control property and control. The binding can be established by the createEx function by program or by using the graphical tools. exists takes 2 parameters. If either has not been done then it will return false.

propertyName:  Name of the property, for example, Text, Left, Top, etc. These properties can be set.

Control: (reference to a control,   for example,  var myControl = TcHmi.Controls.get(‘TcHmiTextbox_1’);)


TcHmi.Binding.resolveEx => Returns a symbol expression (for example ‘%i%MyInternalSymbol_1%/i%’,  ‘%s%PLC1.MAIN.varIntPlcVariable%/s%’  etc) if a binding exists between a symbol and the control attribute or null if no binding exists.  This function takes 2 parameters:

propertyName:  Name of the property, for example, Text, Left, Top etc. These properties can be set.

Control: (reference to a control,   for example,  var myControl = TcHmi.Controls.get(‘TcHmiTextbox_1’);)

var myControl = TcHmi.Controls.get('TcHmiTextbox_1');
    var result = TcHmi.Binding.exists('Text',myControl);
         console.log("Binding exists");
    } else {
         console.log("Binding does not exist");
    var symbolExpression = TcHmi.Binding.resolveEx('Text',myControl);
         console.log(myControl.getId() + '::Text is bound to symbol expression: ' + symbolExpression.toString());
    } else {
console.log(myControl.getId() + '::Text is bound to symbol expression: ' + symbolExpression.toString());


How to make PLC data available to HMI Server

=> First we need to give access to the PLC. The PLC can be in the local network, remote network, or even the local machine (PLC program is running in the same machine). The PLC is identified by the Ams NetId.

=> If the PLC is in the network then the HMI Server computer (where the HMI Server is running) should have the route, for details see how to add a route for searching Beckhoff PLC.

=> If the PLC is running on the local PC, we add the localhost address “” + “1.1”

=> For remote machine, it is wise to set the AmsNetId to  IP address + .1.1,  this help to remember the AmsNet Id, see how to change Ams Net Id

=> You can bring the left-hand side setting dialog by selecting HMI Project | Server and then from the menu  TWINCATHMI | TwinCAT HMI Server Configuration.

=> Set Enabled to true, AmsNetId and the port number and press accept.

Note: In some smaller controller Symbol name is not supported, in this case the data can be accessed directly by using indexGroup and indexOffset (in that case,  we press on Symbols and then Add)

Mapping variables to TwinCAT HMI

Adding Ams Net Id establishes a link between the HMI Server and the PLC. HMI Server does not know what kinds of variables are available in the PLC yet. The mapping process establishes a  connection between HMI Server and the PLC so that HMI Server can read those data over the ADS protocol.



=> Select the HMI project and then Server in the solution explorer

=>Now select the HMI Configuration as shown in the left image


1 => Shows all the variables in the PLC Main

2 =>Mapped Symbol (the variables which have been mapped)

3 => Internal symbol to the HMI server

4 => Localization of this application (see more).

5 => Built-in function provided by TwinCAT framework.



=> Select the HMI project and then Server in the solution explorer while HMI project is selected

=>Now select the HMI Configuration as shown in the left image

=> If we press on the All Symbols then it will show all PLC variables under the MAIN PLC, if this does not show any variables then refresh the configuration

=> To map a variable, we right click on the PLC variable and select and select Map Symbol and press OK. Now this variable will be available in the HMI

=>We can map all the necessary variable one by one or selecting all by in single mapping.

=>Mapped Symbols will show all the mapped variables in the system


Server Symbols

Server symbols can be created centrally in the server under Mapped Symbols. They can also be used offline without a PLC. Clicking on the button Create Server Symbol opens a dialog for adding server symbols. Server symbols can be used to hold some internal variable for processing  business logic. This can be mapped to PLC variable as well. This variable can be persistent meaning if the server restarted the value is saved.

=> Right click on the Mapped Symbols

=> Select create new server symbol

=> Fill the necessary information as shown in the following image

Internal Symbols

Internal symbols are independent of the server and are valid within a browser instance. The internal symbols thus enable variables to be saved individually for each client.

=> Internal Symbol can be created as same way as server symbols

=> Right click on the internal symbol and fill the necessary information as shown in the following image

Test Application

The test application can be downloaded from and test.

Here is a short description of what the test application does.

1=> An internal symbol is displayed here (the internal symbol has been bounded manually),

2=>If we press on this button the internal symbol will increase by one,

3=>Internal symbol will decrease by one,

4=>If we press on this button it will read the value of edit box 5 and set it to PLC, this button’s left property is bound with the internal symbol, so if we increase or decrease the internal symbol, this button will move left or right.

5=>Display the current value of the PLC variable if there is binding. If there is no binding then it will be empty

6=>If we press on this button the PLC variable (we have a single variable) will be bound to the edit box at 5

7=>If we press on this button the PLC variable (we have a single variable) will be unbounded to the edit box at 5 and it will display nothing (because it is not bound to anywhere)

8=>Display the binding status if we press on 6 or 7 or even during the initialization of the program.

We embedded JavaScript code for binding and unbinding. For test purpose we have embedded JavaScript for editbox (5). The code can be found in the downloaded zip file.

var myControlInt = TcHmi.Controls.get('TcHmi_Controls_Beckhoff_TcHmiTextbox_IntPLCVariable');
if(myControlInt){     var result = TcHmi.Binding.exists('Text',myControlInt);     if(result){          console.log("Binding exists with IntPLCVariable");     } else {          console.log("Binding does not exist with IntPLCVariable");     } }
if(myControlInt){     var symbolExpression = TcHmi.Binding.resolveEx('Text',myControlInt);     if(symbolExpression){                   console.log(myControlInt.getId() + '::Text is bound to symbol expression: ' + symbolExpression.toString());     } else {          console.log("Binding does not exist with IntPLCVariable, symbol expression is null");     } } 

We have embedded the following code for button number 6 (to make the binding), for unbinding, we have a little bit of different code that can be check by copying the code.


var myEditBoxControl = TcHmi.Controls.get('TcHmi_Controls_Beckhoff_TcHmiTextbox_IntPLCVariable');
var myMsgBoxControl = TcHmi.Controls.get('TcHmi_Controls_Beckhoff_TcHmiTextblock_Message');
if (myEditBoxControl && myMsgBoxControl) {
    TcHmi.Binding.createEx('%s%PLC1.MAIN.varIntPlcVariable%/s%', 'SetText', myEditBoxControl);
    var result = TcHmi.Binding.exists('Text',myEditBoxControl);
        myMsgBoxControl.setText('Binding Done');
    } else {
        myMsgBoxControl.setText('Binding not Done');

Tips 01: Why my HMI does not updated with initial value set in the server or in server extension?

Data need to changed if we want to display data on the UI. One way to configure the UI with custom events as shown in the following image.

Tips 02: I see warning symbols besides my mapped variables, why it is shown in the following image.

The reason for this you have a running runtime with previous variables mapped (from other PLC programs).

Sol: just unmap these variables or check if the PLC is in run mode.