User Tools

Site Tools


Optimizing performance

To understand the principles of WebHMI operation, let's analyze how its kernel works.

Schematically, the structure of the core of the system can be represented as follows:

The kernel works cyclically. This means that all actions are performed sequentially. If delays occur at some stage, this affects the execution time of the entire cycle.

Let's look at each of the blocks in this diagram.

Configuration read

Immediately after the system is booted up, the project is loaded into the main memory. At that moment, the values ​​of all volatile registers are reset to zero, the state of all events is set to 'not executed'. If the user makes any change to the settings of registers, connections, events, scripts, etc. the kernel re-reads the configuration after the end of the current cycle. All the values ​​of the registers will be reset, events will also be interrupted. Therefore, changing the configuration of the project during commercial operation can cause interruption of events and resetting of registers that are in energy-dependent memory. We do not recommend changing the project 'on the fly' without extreme need.

When the project settings are read, the kernel enters the main loop.

Writing new values to registers

At the beginning of the cycle, the new values ​​are written to the registers. The system has a special queue for writing new values ​​to the registers. There are 2 ways to write data to the register - through the API and through scripts. In both cases, the recording does not occur when the request comes (because the system may not be ready for this, for example, the RS-485 is already exchanging with the PLC) and later, at the appropriate time. A write request is sent to the queue. All write requests will be executed at the beginning of the next main loop.

Registers read

Further, the registers are read from external devices and internal registers of WebHMI. Registers are read in groups. Grouping occurs by their connection. For example, if the project has a connection to a Delta PLC, Siemens PLC and internal WebHMI registers, the reading will look like this:

  1. All registers from Delta PLCs are read.
  2. All registers from Siemens PLC are read.
  3. All internal registers of WebHMI are read

Internal WebHMI registers are always read last (since they contain registers C0, C1, C2 … in which the read errors from the remaining connections are stored).

Immediately after reading, the necessary value transformations (multiplication, constant additions, casting, etc.) take place.

If there is a stabilization pause for any of the connections, then there will be a corresponding pause before reading the register group of this connection. This is sometimes necessary for the stable operation of heterogeneous devices on one RS-485 bus. Without this pause, some devices may not be able to determine the start of the message frame and skip the first packet to read the first register.

Also, the connections have a Timeout setting. This is the time that the system will wait for a response from the devices on its request. If the devices did not respond within the specified time period or answered the entire packet of data, the system will assume that the register has not been read. Its value will be set to -1, and the register status to invalid.

This means that if there is no connection with one of the external devices, the total polling time (the minimum length of the main loop) will increase by Timeout × The number of registers in this connection.

Here is an example. We have a connection to the Delta SX2 PLC via ModBus RTU. We read from it 5 registers at a speed of 115200. Timeout is set to 100 ms. The average time for reading all five registers is 30 ms (you can see it in the internal register of WebHMI T1). If the connection to the PLC is lost for any of the reasons, then the average read time of all five registers will theoretically increase to 5 × 100 ms = 500 ms (and in practice will be approximately 525 ms).

This means that if there is polling of an unconnected device in the project, then this will slow the entire cycle for a significant amount of time. If it is necessary to minimize this delay, then it is necessary to maximize the exchange rate and reduce Timeout and Stabilization pause. But the best thing is to either reconnect with the device or disconnect this connection in the settings.

Running scripts

After the registers have been read, the kernel executes the scripts. Scripts (or programs) are carried out very quickly and there should not be delays here with a reasonable number and complexity of scenarios. The only feature that you should pay attention to is the difference in the operation mechanism of the Set and Write operations.

The Set operation will change the value of the specified register immediately, at the same place in the main loop. And it will only change the value in the kernel's RAM. The new value will not be written to external devices and will only be available until the end of the current cycle.

The operation Write does almost everything as Set does with the only difference that it adds a command of writing a new value to the write queue. And at the beginning of the next cycle, this value will be written to the appropriate register of the external device.

Note that if there is a condition in the script and any register from this condition has not been read in the current loop, then this condition will not be handled. And, accordingly, actions from this condition will not be performed.

Calculating register states

By this point in the main loop, the values ​​of all the registers have already been computed and will not change later. Therefore, it is at this point that states (invalid / disabled / normal / warning / alert) are calculated for each register .

Processing Events

After all data is collected and prepared, the mechanism for identifying and processing events is triggered.

Event processing starts with checking the condition of the event. Similar to scripts, if any register from the condition was not read in the current loop, then this condition will not be handled. And accordingly the whole event will not be processed.

If the event does not have an extension in time, then the condition for its occurrence is checked in each cycle. And each time this condition is met, the actions for that event will be executed. In each subsequent cycle, if the condition is fulfilled again, then this will be a new occurrence of the event and the actions will be performed again.

If the event has a length in time, then it has an execution state. This is the flag that tells the kernel that the condition is met. Such an event can start executing in one cycle and will end in the other. It can last as long as you like (but with any change to the configuration of the WebHMI project, this flag will necessarily be reset).

When the condition of the event start is fulfilled, the execution flag is set to true. If the end condition (if it is set) or when the condition of the beginning is not fulfilled (if the end condition is not specified), the flag is reset to false.

While this flag is true, all actions for this event are executed. This flag can also be read from internal WebHMI registers at ESx addresses, where x is the event ID. Note that the first “true” value will be calculated in the scan followed the one in which this value was set to true.

Besides the actions available for events, there is a record of information about the event in the database. It should be understood that this operation is resource-intensive. Therefore, it is recommended to write data as rarely as possible. And collect only the necessary data. It makes no sense to write all the registers to the database in each cycle, if it is enough to collect data on the five required registers with an interval of 5 seconds. Also, enhancing too much data details will likely lead to a heavy load on the SD card and its increased wear.

So follow the common sense in data collection and gather only the data that is really needed in your project.

One of the options when saving event data is to record a slice of register values ​​every N seconds. In fact, it is implemented so that the recording will occur no more often than every N seconds from the last record in the database. Here it is necessary to explain the peculiarity of the operation of this interval. It is best to do this with an example.

Example. The kernel reads 150 ModBus registers, the average cycle length is 1.3 seconds. The event is set to record data every 5 seconds. Assume that the event is executed for the first time in T + 0.0 seconds. The data was written to the database also in T + 0.0 seconds.

In the next cycle, the event is still running. The time from the last recording is T + 1.3 seconds. 1.3< 5 sec. so writing to the database does not happen. In the next event cycle, the event is still running. The time since the last recording is T + 2.6 seconds. 2.6 < 5 sec. so writing to the database does not happen. In the next cycle, the event is still running. The time from the last recording is T + 3.9 seconds. 3.9 < 5 sec. so writing to the database does not happen. In the next cycle, the event is still running. The time from the last record is T + 5.2 seconds. 5.2 > 5 sec. so the record in the database will occur. Next, the system will compare the time with the moment T + 5.2.

Note that the actual time between records will be 5.2 seconds and not 5. Because the system displays the time with a second accuracy, this can cause the time between records to be displayed as 6 seconds, and for some variations even 7 seconds (for example, the first record was in T + 0.9 and the second in T + 6.1).

I.e. due to the fact that the length of the cycle can be unstable, then the actual data recording interval will also depend on this length. The system will behave optimally if the specified interval of the interrogation of devices (Communication interval) exceeds the actual length of the cycle and the recording in the database is conducted with a multiple interval (Communication interval).

Preparing register values ​​for the API

After processing the events, the kernel will prepare a list of all the registers, their states and values, and pass it to the API. After that, the responses from the API about the current values ​​of the registers will contain the data obtained in the current cycle.

Writing values ​​to the database

At this stage of the cycle, the current values ​​of the registers are written to the log. Only those registers for which the corresponding option is included are written to the log. If the option to record graphs for the register is enabled, then data is recorded for plotting.

Recording to an SD card is a slow operation. Therefore, recording a large number of values ​​with a high frequency of changes can take a significant amount of time and system resources. It also consumes an SD card resource.

Therefore, it is recommended to write to the log only those registers that are really needed. We also recommend writing them not too often. Recording 10-20 parameters every second can significantly load the system, reduce the responsiveness of the interface, increase the cycle length.


After all the operations have been completed, the system determines how much time was actually spent for the current cycle. If this time is less than the Communication interval setting, the system will pause for the difference [Communication interval - actual time] so that the total cycle length is exactly the time specified in the Communication interval.

This means that if the actual cycle time is greater than the Communication interval, the system will not pause and will not be able to poll the devices with the specified periodicity.

If it is necessary to “fit” the specified interval, then there are several ways of optimization:

  1. Increase the speed of exchange on the RS-485, RS-232 buses. The speed of 9600 is too slow for a lot of data. We recommend selecting a speed of 115200 and higher.
  2. If there are a lot of registers and not all need to be polled in each cycle, then you can specify a larger poll interval for less important registers. This will offload the system and data buses.

General rules for optimizing your projects

At the time when the WebHMI was invented, it supposed to be used in relatively small projects. But with time, more and more customers installed them for quite big projects. Also, the functionality of the front-end part has been increasing constantly, so that when you're going to use it in the project with thousands of tags with the device fw above 3.5, you should remember about finite platform resources you have. Below there are several considerations you may follow to keep you project fast and responsive:

Keep the number of registers in the project below 2-3K

Each register in the project has a lot of configuration data associsted with it, the bigger the register tree, the more load will lay upon the system. That may slow down the response when you work with the register tree. Organize your register tree in categorites.


  1. Use screens wherever is possible for visualisation, and use dashboards as a part of screens for graphic part, which can not be done with the screens.
  2. Avoid using bulky dashboards (too rich in elements, having heavy-weight pictures etc. ), “normal” dashboard is about tens of KB, not MB! (you can check dashboard size exporting it into en external file)
  3. Set appropriate screen refresh time.
  4. use templates for dashboards, alerts and others


  1. Avoid using many scripts. The better way is using a few big scripts or scripts with libraries instead of a lot of small scripts (each script takes some os environment). Best practice is when script list fits into one page, and each scripts fits into editor windows w/o scrolling it down.
  2. Run scripts upon changing value, minimize the number of scripts, running in each scan.
  3. Minimize “WriteReg” Lua instructions in each scan. Becuase WriteRegs are placed into the writing queue, a heedless loop, or using WriteReg in the 100 scripts to update some logic results in creating write queue for 100 tags in each scan (remember each register actually mean a big data sctucture of its properties). It is better to use wrapping function UpdReg() like this:
function UpdReg(reg, new_value)
    local cur_value = R(reg)
    if (not cur_value) or (not new_value) or (cur_value == new_value) then 
        return false 
        WriteReg(reg, new_value)


  1. Use group registers feature
  2. Set appropriate timeout and tries in external connections E.g. if the device has common timeout of 30 ms, set it about 40 ms. If the device gets lost, with bigger timeout set to 100 ms, each scan it will take extra 60 ms on read tries. Use “skip”, “auto-drop & probe” options for not stable connections.
  3. Organize and set different reading intervals for variables. E.g. for device settings (like PID coeficitens, tolerances and other setup data) you set “Read-On-Demand” property, for slow parameters, like temperature you set 1 minute and so on.
  4. For mulitple external devices, you can use “sliding” connection window trick to temprorarily access a device.

Project editing

  1. Keep the number of open tabs in browser minimal for the current session. If you need multiple tabs, use auto-close session checkbox to prevent unattended access.
  2. Avoid making multiple changes in series, like turning OFF-ON many regs, connection, scripts etc. Use save & apply feature of the latest fw. (apply all changes at once, instead of creating a queue for changes)

Track Load Average parameter

There is a metric register in the internal register showing mean number of the processes in the queue relative to the running process. There are 1, 5, 15 minutes mean paratemer. In a steady state, you 15 minutes metric should be below 1.

Optimize log

  1. Minimize logging many registers to DB, set appropriate log speed for them. When setting 'use data from log' for the graphs, make sure you limit the log amount with the setting.