LLExec Web Server

From Axel Public Wiki
Jump to navigation Jump to search

Server API

This section describes the internal API that LLExec integrated Web Server offers to access PLC variables and parameters.

Please note that this API is wrapped by the LLWebServer library, that should be used instead.

Variables access

To access variables (also called symbols), the web server offes two http methods: GET to read simple variables and PUT to write simple variables.
The symbols that can be accessed are global variables of simple types (numeric, boolean, string).
The symbols can also be structured query of the type my_arr[123].my_field, with the constraint that the value of the expression must be of simple type.

GET symbols method syntax

The syntax of the url to do the GET method:

http://1.2.3.4/api/sym?sym_name1&sym_name2&sym_name3

The content value of any symbol will be written on a single line.

PUT symbols method syntax

The syntax of the url to do the PUT method:

http://1.2.3.4/api/sym?sym_name1=value1&sym_name2=value2&sym_name3=value3

Where the valueN is the value of the variable N. String values doesn't need limiters, and spaces must be coded in the URL with the string %20 . For example:

PUT http://1.2.3.4/api/sym?var_bool=true&var_int=123&var_string=hello%20world

Parameters access

To access parameters web server offes two http methods: GET to read parameters and PUT to write parameters.
To access parameters their index must be known, eventually with subindex (this indexes are called IPA): IPA examples are 10000.12 or 60000 .

GET symbols method syntax

The syntax of the url to do the GET method:

http://1.2.3.4/api/par?ipa1&ipa2&ipa3

The content value of any parameter will be written on a single line.

PUT symbols method syntax

The syntax of the url to do the PUT method:

http://1.2.3.4/api/par?ipa1=value1&ipa2=value2&ipa3=value3

Where the valueN is the value of the variable N. String values doesn't need limiters, and spaces must be coded in the URL with the string %20 . For example:

PUT http://1.2.3.4/api/par?10000=true&10010=123&10021=Hello%20world

Browsing variables

The Web Server offers a method to obtain information about variables on the system.
The url for browsing symbols have to be called with http GET method and is as follows:

http://1.2.3.4/api/symlist?name=pattern

The pattern can be a variable name, the jolly * character, or a name with the jolly character prefixed or suffixed.
Examples are

http://1.2.3.4/api/symlist?name=*
http://1.2.3.4/api/symlist?name=my_variable_name
http://1.2.3.4/api/symlist?name=count*
http://1.2.3.4/api/symlist?name=*substr*

The output of the query is a JSON containing the list of the symbols that matches the pattern, with attributes like name, type and description.
For example, if in my system i do the query

http://127.0.0.1/api/symlist?name=*

I obtain the following output:

[
	{ "name":"$$STKLIMIT$$", "type":"LWORD", "descr":""},
	{ "name":"$$STKPOINTER$$", "type":"LWORD", "descr":""},
	{ "name":"$$DEBUGID$$", "type":"DWORD", "descr":""},
	{ "name":"CNT", "type":"INT", "descr":""},
	{ "name":"SYSPLCSTATUS", "type":"PLC_STATUS", "descr":"Internal PLC Status"},
	{ "name":"SYSTIMER", "type":"UDINT", "descr":"System timer [ms]"},
	{ "name":"SYSPLUGINSDATARO", "type":"BYTE", "descr":"RO allocation area for plugins"},
	{ "name":"SYSPLUGINSDATARW", "type":"BYTE", "descr":"RW allocation area for plugins"},
	{ "name":"SYSUSERDATABLOCK", "type":"BYTE", "descr":"Data block available for user data mapping"},
	{ "name":"SYSUSERDATABLOCKRETAIN", "type":"BYTE", "descr":"Data block available for user data mapping - Retain DB"},
	{ "name":"SYSHOURS", "type":"USINT", "descr":"Values 0-23"},
	{ "name":"SYSMINUTES", "type":"USINT", "descr":"Values 0-59"},
	{ "name":"SYSSECONDS", "type":"USINT", "descr":"Values 0-59"},
	{ "name":"SYSDAY", "type":"USINT", "descr":"Values 1-31"},
	{ "name":"SYSDAYOFWEEK", "type":"USINT", "descr":"Values 0-6 where 0 is Sunday "},
	{ "name":"SYSMONTH", "type":"USINT", "descr":"Values 1-12"},
	{ "name":"SYSYEAR", "type":"UINT", "descr":"Values 4 digit"},
	{ "name":"SYSCOPMSDOFAILEVENT", "type":"COPMSDOFAIL", "descr":"This struct is filled just before an occurred parametrization SDO fail is signaled to PLC task"},
	{ "name":"SYSCOPMNODESTATUSCHANGEDEVENT", "type":"COPMNODESTATUSCHANGED", "descr":"This struct is filled just before a node status change is signaled to PLC task"},
	{ "name":"SYSCOPMEMERGENCYEVENT", "type":"COPMEMERGENCY", "descr":"This struct is filled just before an occurred emergency event is signaled to PLC task"},
	{ "name":"SYSCOPMPDOERREVENT", "type":"COPMPDOERR", "descr":"This struct is filled just before a malformed PDO RX event is signaled to PLC task"},
	{ "name":"SYSCOPMEVENTID", "type":"DINT", "descr":"This value is set with the event ID value. The struct corresponding to the ID set can be used in the notify event task when it is executed"},
	{ "name":"SYSCOPMRESYNCINFO", "type":"COPMRESYNC", "descr":"This struct is filled just before a master/slave resync event"},
	{ "name":"SYSCOPMMASTERSTATUS", "type":"COPMMASTERSTATUS", "descr":"See structure definition COPMMASTERSTATUS"},
	{ "name":"SYSCOPMNODESTATUS", "type":"COPMNODESTATUS", "descr":"See structure definition COPMNODESTATUS"},
	{ "name":"SYSCOPMSDOSCHEDULINGDIAGNO", "type":"COPMSDOSCHEDULINGDIAGNO_SLAVE", "descr":"This structure show for each node the last SDO scheduled succeded and failed"},
	{ "name":"SYSMBMRTUNODESTATUS", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_0. ..."},
	{ "name":"SYSMBMRTUNODESTATUS_1", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_1. ..."},
	{ "name":"SYSMBMRTUNODESTATUS_2", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_2. ..."},
	{ "name":"SYSMBMRTUNODESTATUS_3", "type":"MBMNODESTATUS", "descr":"System Modbus Master RTU communication status for network with id MB_RTU_NETWORK_3. ..."},
	{ "name":"SYSMBMTCPNODESTATUS", "type":"MBMTCPNODESTATUS", "descr":"System Modbus Master TCP communication status. It is a structure of type MBMTCPNODESTATUS composed ..."},
	{ "name":"SYSALARMCFGOK", "type":"BOOL", "descr":"Alarm manager properly configured"},
	{ "name":"SYSALARMACTIVE", "type":"BOOL", "descr":"At least one alarm is active (associated condition holds true)"},
	{ "name":"SYSALARMWAITACK", "type":"BOOL", "descr":"No alarm is active but at least one alarm is waiting for acknowledgement"},
	{ "name":"SYSALARMCOUNT", "type":"UINT", "descr":"Number of active alarms"},
	{ "name":"SYSPLCCONNECTMASTERSTATUS", "type":"PLCCONNECTMASTERSTATUS", "descr":""},
	{ "name":"SYSPLCCONNECTENDPOINTSSTATUS", "type":"PLCCONNECTENDPOINTSTATUS", "descr":""},
	{ "name":"$$CODEBASE$$", "type":"UDINT", "descr":""},
	{ "name":"$$CODESTART$$", "type":"UDINT", "descr":""},
	{ "name":"$$CODESIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$CODEEND$$", "type":"UDINT", "descr":""},
	{ "name":"$$DATASIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$AUXDATASIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$BITDATASIZE$$", "type":"UDINT", "descr":""},
	{ "name":"$$RITDATASIZE$$", "type":"UDINT", "descr":""}
]

Browsing parameters and menus

LogicLab allows to define application parameters and status variables, with an IPA a type and some others attributes.
From the perspective of the web server, parameters and status variables are the same type of objects, so we simply refer as parameters.
In LogicLab you can also define menus in wich some parameters can be contained: every menu is identified by an unique id.
Menus can be nested.
An user can define also custom web pages, that can be nested also in mixed mode with menus, they have theirs own unique id.
The web server offer two API to browse menus, custom pages and parameters, both can be called with the GET http method. The two urls are:

http://1.2.3.4/api/parlist?id=unique_id_of_a_menu
http://1.2.3.4/api/menulist?id=unique_id_of_a_menu&recursive=[TRUE | FALSE]

Parlist API

With this API an user can query the list of parameters contained in a menu, specified with its id
If the id is set to 0, all the application parameters are listed.
The output is a JSON containing the list of parameters with teirs attributes.
For example if I query the url

http://127.0.0.1/api/parlist?id=0

to my server I obtain the following output:

[
	{ "ipa": 1, "name": "Par 1", "typepar": "short", "readonly": false, "defval": 0, "descr": "", "form": "", "um": ""},
	{ "ipa": 10001, "name": "Par 2", "typepar": "short", "readonly": true, "defval": 0, "descr": "", "form": "", "um": ""}
]

The attributes that can be found for every parametes are:

  • ipa: the IPA of the parameter
  • subindex: if presemt, the subindex of the parameter. Note that the subindex presence depends on how LogicLab manage the address of parameters.
  • name: the name of the parameter.
  • typepar: the type of the parameter.
  • readonly: the attribute read-only of the parameter.
  • defval: the parameter's default value.
  • descr: the description of the parameter.
  • form: the printf-style desired format.
  • um: the measure unit for the parameter value.

Menulist API

With this API an user can query the menus and custom pages structure,
the id specifies the starting node, if zero it shows all the root menus.
If the recursive parameters is TRUE, nested menus and custom pages are shown.
For example if on my system I query the url

http://127.0.0.1/api/menulist?id=0&recursive=TRUE

i obtain the foolowing JSON output:

[
  { type: 0, id: 30000, caption: "MyMenu", children: 
    [
      { type: 0, id: 30001, caption: "Nested Menu" },
      { type: 1, id: 30002, caption: "Nested Custom Page", link: "custom.html", icon: "custom.ico" }
    ]
  }
]

the attributes are:

  • type: 0 is a menu, 1 is a custom page
  • id: the menu or custom page unique id
  • caption: the menu or custom page title
  • link: only for custom pages, its URL
  • icon: only for custom pages, its icon
  • children: when recursive=TRUE, this is a list of nested elements

System API

With the System API is possible to stop, start and get the status of LLExec runtime
It's also possible to read the LLExec Logs.
The API is composed of the following commands, all retrieving JSON responses:

  • /api/sys/start
  • /api/sys/stop
  • /api/sys/restart
  • /api/sys/status
  • /api/sys/log

start command

With the command /api/sys/start, without parameters is it possible to start the PLC.
Example:

http://127.0.0.1/api/sys/start

produces the following output:

{
 "plcCommand":"start",
 "result":"success"
}

stop command

With the command /api/sys/stop, without parameters is it possible to stop the PLC.
Example:

http://127.0.0.1/api/sys/stop

produces the following output:

{
 "plcCommand":"stop",
 "result":"success"
}

restart command

With the command /api/sys/restart, without parameters is it possible to restart the PLC.
Example:

http://127.0.0.1/api/sys/restart

produces the following output:

{
 "plcCommand":"restart",
 "result":"success"
}

status command

With the command /api/sys/status, without parameters is it possible to get some information about PLC runtime.
Example:

http://127.0.0.1/api/sys/status

produces the following output:

{
 "plcCommand":"status",
 "result":"success",
 "status":"sysStatusStarted",
 "runtimes" : 
 [{
   "rtid":"0",
   "targetid":"LLExec_x86_2p0",
   "numtask":"5",
   "numdatablocks":"33",
   "numfunctions":"221",
   "datasize":"262144",
   "retsize":"4096",
   "bitsize":"0", 
   "codesize":"1048576",
   "debugsize":"0",
   "tracesize":"0",
   "srcsize":"0",
   "plcok":"true",
   "plcalarm":"false",
   "plcerrcode":"0",
   "appname":"LLSDO     ",
   "vermajor":"0",
   "verminor":"0",
   "appid":"1818769352"
 }]
}

log command

With the command /api/sys/log is it possible to get the actually buffered logs of LLExec.
It has three optional parameters:

  • mask - the exadecimal log print mask
  • startLine - the line where logging starts (default = 0)
  • numLines - Number of lines to print (default till the end of the log buffer)

Example:

http://127.0.0.1/api/sys/log?mask=FF&numLines=10

produces the following output:

{
 "plcCommand":"log", 
 "result":"success", 
 "lines":
  [ 
   { 
    "time":"00000000",
    "code":"00000001",
    "callId":"794EF2CA",
    "line":"LLEXEC 2.15.11 (Build: Apr 20 2020 15:15:20 32bit)"
   }
   ,{ 
    "time":"00000001",
    "code":"00000001",
    "callId":"794EF2CA",
    "line":"LLEXEC Starting up..."
   }
   ,{ 
    "time":"00000002",
    "code":"00000002",
    "callId":"794ECB94",
    "line":"Tracing: Configuration level"
   }
   ,{ 
    "time":"00000003",
    "code":"00000004",
    "callId":"794ECBA3",
    "line":"Tracing: Scheduler level"
   }
   ,{ 
    "time":"00000004",
    "code":"00000008",
    "callId":"794ECBB2",
    "line":"Tracing: Basic communication level"
   }
   ,{ 
    "time":"00000005",
    "code":"00000010",
    "callId":"794ECBC1",
    "line":"Tracing: XML configuration file level"
   }
   ,{ 
    "time":"00000006",
    "code":"00000020",
    "callId":"794ECBD0",
    "line":"Tracing: Fault and PLC debug informations"
   }
   ,{ 
    "time":"00000007",
    "code":"00000040",
    "callId":"794ECBDF",
    "line":"Tracing: General purpose message of advenced level"
   }
   ,{ 
    "time":"00000008",
    "code":"00000001",
    "callId":"794EF2CA",
    "line":"** Loading configuration"
   }
   ,{ 
    "time":"00000009",
    "code":"00000010",
    "callId":"794EF2CA",
    "line":"XML: overtime check : 0"
   }	
  ]
}

Reference Table

List of commands
Command Output type HTTP method Parameters Description
/api/sym list of values GET list of symbol names Get the values of the specified symbols
/api/sym list of values PUT list of symbol=value pairs Set the values of the specified symbols
/api/par list of values GET list of IPAs Get the values of the specified parameters
/api/par list of values PUT list of ipa=value pairs Set the values of the specified parameters
/api/symlist JSON GET name=pattern Get the symbols list
/api/menulist JSON GET id (unique id), recursive (TRUE FALSE) Get the list of child menus from a menu with a specified menu id
/api/parlist JSON GET id (unique id) Get the list of the parameters in the menu entry
/api/sys/start JSON GET NA Starts the runtime
/api/sys/stop JSON GET NA Stops the runtime
/api/sys/restart JSON GET NA Restarts the runtime
/api/sys/status JSON GET NA Get the runtime status
/api/sys/log JSON GET mask (print mask), startLine (first line to get), numLines (number of lines to get) Get the runtime logs

Client library

This section describes the LLWebServer.js library and its features.

In order to use the library, you have to create HTML Elements with some specific data attributes; LLWebServer will find them in the web page and will take care of managing their data and their values.

The accepted data attributes are:

  • data-llweb-sym: used to link a PLC symbol on server the to the HTML Element
  • data-llweb-par: used to link a PLC parameter on server to the HTML Element
  • data-llweb-img: associated to a symbol or a parameter, with an img HTML Element, allows to display an user-defined image that corresponds to a value read from the server
  • data-llweb-refresh: flag used to set the automatic refresh on an HTML Element
  • data-llweb-format: sprintf format to format values

An explanation for each one is provided in the following sections.

Creating controls

Symbol input field

Here's an example how to create a simple input text field using the data-llweb-sym attribute.

<input type="text" data-llweb-sym="cnt">

cnt is the symbol name and it's used to link the PLC symbol on the Web Server to the HTML Element, so that you can read and write it.


Parameter input field

Here's an example how to create a simple input text field using the data-llweb-par attribute.

<input type="text" data-llweb-par="10001">

10001 is the parameter IPA and it's used to link the PLC symbol on the Web Server the to the HTML Element, so that you can read and write it.


Image control

Here's an example how to create an image control using data-llweb-sym combined with the data-llweb-img attribute.

<img data-llweb-sym="myEnum" data-llweb-img="2:error.gif, 1:true.png, 0:false.jpg" alt="missing image">

The LLWebServer library will get from the data-llweb-img attribute a list of items separated by comma. Each item has a value and an image; before the colon there's the symbol value and after the associated image, like this: Value:ImageName.jpeg.

When the value of myEnum symbol is read from the server, if myEnum == 2 the image source will be error.gif, if myEnum == 1 will be true.png and if myEnum == 0, false.jpg.

In the following example, the read value is 1 and the src attribute img/true.png is set from the LLWebServer library.

<img data-llweb-sym="myEnum" data-llweb-img="2:error.gif, 1:true.png, 0:false.jpg" alt="missing image" src="img/true.png">

As you can see, you can specify whatever image format you want.

The img HTML Element can also write values: if you click on the image, the next value listed in the data-llweb-img attribute will be written. Of course you can make an image read-only adding data-readonly="true" attribute, since images are natively read-only in HTML and do not suppor standard "disabled" or "readonly" attributes.

Note: the image file must be in a img folder in the same path of the HTML page.


Some examples

Select control example

<select data-llweb-sym="myBool" data-llweb-refresh="true">
	<option value="0">false</option>
	<option value="1">true</option>
</select>

Checkbox control example

<input type="checkbox" data-llweb-sym="myBool" data-llweb-refresh="false" disabled>

Radio button control example

<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="1" id="rad-ctrl-myEnum-1" data-llweb-refresh="true">
<label for="rad-ctrl-myEnum-1">one</label>
<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="2" id="rad-ctrl-myEnum-2" data-llweb-refresh="true">
<label for="rad-ctrl-myEnum-2">two</label>
<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="3" id="rad-ctrl-myEnum-3" data-llweb-refresh="true">
<label for="rad-ctrl-myEnum-3">three</label>
<input type="radio" data-llweb-sym="myEnum" name="rad-myEnum" value="4" id="rad-ctrl-myEnum-4" data-llweb-refresh="true">
<label for="rad-ctrl-en2var-4">four</label>

Button control example

You can also use buttons to directly write a value on the web server:

<button data-llweb-sym="myEnum" value="1">one</button>
<button data-llweb-sym="myEnum" value="2">two</button>
<button data-llweb-sym="myEnum" value="3">three</button>
<button data-llweb-sym="myEnum" value="4">four</button>

Updating controls

You can manually update the values in HTML controls calling the JavaScript function UpdateControls, for instance when a button is pressed.

LLWebServer.UpdateControls();

The UpdateControls function will update once all the controls in the page with data-llweb-par or data-llweb-sym attributes.


Otherwise the LLWebServer library supports an autorefresh feature that automalically refreshes all the values with the data-llweb-autorefresh attribute.
For example, in the image control example above, you can add data-llweb-autorefresh="true" to enable autorefresh.

<img data-llweb-sym="myEnum" data-llweb-img="2:error.gif, 1:true.png, 0:false.jpg" alt="missing image" data-llweb-refresh="true" >

Once you defined HTML Elements with the data-llweb-autorefresh attribute, you have to call the JavaScript function AutoRefreshStart specifying the refresh timeout in milliseconds after each request.

In the following example, the autorefresh is started with a timeout of 500 milliseconds:

const TIMEOUT_MS = 500;
LLWebServer.AutoRefreshStart(TIMEOUT_MS);

To stop the autorefresh, use the function AutoRefreshStop:

LLWebServer.AutoRefreshStop();

Of course you can use the data-llweb-autorefresh attribute on image, input, select, radio and checkbox HTML controls.

Note: when you edit a value while autorefresh is enabled, if Enter is pressed the user input will be immediately written on server.

Formatting values

It is possible to format the values in HTML inputs trough the data-llweb-format attribute which uses the C sprintf syntax.

<input type="text" data-llweb-sym="real1" data-llweb-refresh="true" data-llweb-format="%.2f">
<input type="text" data-llweb-sym="cnt" data-llweb-refresh="true" data-llweb-format="%x">

In the first example it's used %.2f to get two decimals of precision while in the second %x to get an hex value.