We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you've provided to them or that they've collected from your use of their services.

Yet another way of talking to your PLC...

A few days ago I received an email from Sergio. He turned my attention towards a WebVisu project developed on SourceForge net by Frank Benkert (https://sourceforge.net/projects/webvisu/). The author managed to decode the protocol of communication between a PLC and the standard, web and JAVA based visualizations. Having the protocol he prepared a code, which re-creates CoDeSys visualization in a web browser using ONLY JavaScript. Sounds fascinating? Oh, because it is!

Here is a short illustration of what it is all about:


In order to see it all in action you need to:

  1. Turn the web visualizations on at Target Settings->Visualization->Web visualization
  2. Prepare a visualization in CoDeSys and upload it to your controller
  3. Download from sourceforge the 'WebVisu.html' file
  4. Upload the 'WebVisu.html' via FTP to your controller to 'webserv' directory
  5. In the browser enter 'http://Controller'sIP/webserv/webvisu.html'

I find the findings of Frank Benkert so exciting for 2 reasons:

  1. He showed a new, undocumented way of communicating with a PLC.
  2. He showed how one can get the addresses of variables, which have not been directly addressed in the program code.


The communication protocol

Communication with the PLC controller is done through POST request sent to /plc/webvisu.htm.

In order to read variables (or physical ins and outs) the request should be structured as follows:

| 0 | number-of-addresses-to-read
| counter-starting-from-zero | address | address | number-of-bytes | variable-type |

Reading two first physical outputs on my controller goes as follows:


The PLC replies:|0|0|

One must not know the address, byte-length or variable type. This information is published by the controller in a plc_visu.xml file. I write about it in the 2nd part of this article.

The change of a variable’s value is done as follows:

| 1 | number-of-addresses-to-write
| counter-starting-from-zero | address | address | number-of-bytes | variable-type | new-value |

In order to change a BYTE variable addressed at %MB6 to 7 I send:


For an amateur like myself, who does not like MODBUS, such a protocol is simple and transparent. It is sufficient to use the following PYTHON code to read first 100 outputs:

import requests 	#you might need to install requests separatelly
req = "|0|100"
for num in range (0,99):
        req+= "|"+str(num)+"|2|"+str(num)+"|1|2"
req+= "|"
r = requests.post('', data=req)
print r.text

The PLC replies:


The time of executing this script on my RPi is 0.2 sec.

In javascriptcie (with jQuery) one could use the following code:

req = "|0|100";
for (var i=0; i<100; i++) {
req += "|"
	type: "POST",
	url: "",
	data: req,
	success: function (data) {

The advantage of the presented protocol over the READPI/WRITEPI request is quite obvious.  One can read a large number of variables very quickly.  It is a great simplification in comparison to constructing a „READPI?ADR=…..&FORMAT=%d” request for each individual variable.  In fact, knowing what I know now, I should rewrite all my code including the jQuery plugin…


You can easily skip the next 4 tech-oriented paragraphs and go directly to the words „One, however, does not need to know all of that”.

In the communication each of the variables is presented as:

| address | address | number-of-bytes | variable-type |

It seems that the first address number is a group. On my controller all variables, which received specific addresses (by using AT %MB…) are placed in group 0. The inputs – 1, outputs – 2, other variables in the program – 4.

My first output DO, has the address %QX3.0. First 3 WORDS were taken by the RS232 communication module. 3 words are 3x16 bits = 48 bits, counting from 0 it is 0-47. That is why the address of %QX3.0 is 2, 48.

The number of bytes depends on the variable type. For physical inputs and outputs it is 0 (?), for BOOL and BYTE it is 1, WORD -2, DWORD – 4, STRING – length+1.

Variable types are: BOOL – 0, INT – 1, BYTE – 2, WORD – 3, DINT – 4, DWORD – 5, REAL – 6, TIME – 7, STRING – 8, ARRAY – 9. Setting the right variable type seems not to be critical. One can read the whole memory in 1-byte pieces. A correct definition of the type gives correctly formatted reply. A 4-char string can be returned as “abcd” if the variable type 8 is requested, or 47821 if the type is 5.

One, however, does not need to know all of that. Another thing described by Frank Benkert is how the variable address used in a visualization are published by the PLC.

Let’s imagine a simple program with the following variables:

	AddressedVariable  AT %MB0 : BOOL;
	StringVariable	: STRING(5);
	ByteVariable : BYTE;
	WordVariable: WORD;

Now, let’s add a visualization named “PLC_VISU” with 4 elements presenting the values of the above-mentioned variables and with a fifth element showing the state of the 1st physical output of the controller. When the program is uploaded (assuming that the option Target Settings->Visualization->Web visualization is checked), in the “PLC” directory of your PLC a file named “plc_visu.xml” will be generated.

At the very bottom of the file you will find:

	<variable name="PLC_PRG.AddressedVariable">0,0,1,0</variable>
	<variable name="PLC_PRG.StringVariable">4,0,6,8</variable>
	<variable name="PLC_PRG.ByteVariable">4,6,1,2</variable>
	<variable name="PLC_PRG.WordVariable">4,7,2,3</variable>
	<variable name=".OUT0">2,0,0,0</variable>

Here are the addresses we were looking for! We can now read their values with the “|0|…” POST request, with the traditional READPI queries and with MODBUS. For me it is like a break-through! I have access to all the data without the laborious addressing made in the code. I can read the value of StringVariable sending"|0|1|0|4|0|6|8|" or of all the above-mentioned addresses with: "|0|5|0|0|0|1|0|1|4|0|6|8|2|4|6|1|2|3|4|7|2|3|4|2|0|0|0|".

Instead of assigning an address (using VAR variable AT %M…) to each variable, which I want to read or change from the outside , I can create a visualization with an element on it, which displays the variable’s value. When the code is uploaded to the controller, the address of that variable will be available in the visualization_name.xml.

An important remark: the location of a variable or a function block in the controllers memory is set by the compiler when the code is generated. Each change of the program might lead to a change of all those addresses. They are not permanent. Every external program willing to use the “un-addressed” variables should each time go through the xml file and search for the current address of the desired variable.

Sergio - many thanks for showing this to me!