We are using Codesys for heavy industrial machinery.
One thing our technicians have to do is to manually operate the system. For that, we have a Webvisu running on a panel pc, with several Tap buttons. They hold the button to operate an hydraulic piston for example.
In my tests I noticed that if, for some reason, the connection is lost while a button is pressed, it will stay pressed. This is very dangerous and can end up in heavy damage.
I'm looking for a way to avoid that. Tried to look at visustructclientdata. But it takes too much time for the client to disconnect. I tried to change the timeout on visustructclientdata, without any success...
Any ideas how to avoid disaster?
With visustructclientdata.GlobalData.LastUsage you can detect, if the webvisu connection is active:
//RemotePanel letzter Zugriff ermitteln
IF pClientDataRemotePanel<>0 THEN
tofRemotePanelUsage(IN:= xRemotePanelUsage, PT:=T#300MS);
heaviest thing is, to get the correct visustructclientdata of the webvisu by iterating all active clients.
this is also very interesting for me.
In another topic I published my code to iterate all the clients...I tried to evaluate when a client disconnects...but it was to slow.
But may with "LastUsage" it will work...:-)
It is in German but you can Download there an example.
I want to do this for a WebVisu Client...
Can you give me an example how to do? I can't find "LastUsage" :-)
LastUsage exists, but is not shown after typing "." (autofill)
I think because you only can get it by a pointer to the visuVisuStructClientData.
Set a breakpoint in your while of the iteration an if a visuclient is active have a look at the pclient variable: in my case now I have only the visu of the programming system active:
found it... but how to use it? If you want to have the data you have to use it in the Method "HandleClient" of FB "VisuClientIteration"
I can't find a solution to use this data...Do you know a solution?
i added the following lines to the while loop of the iteration, like you posted above:
IF pClientData^.GlobalData.ClientType=Visu_Clienttype.WebVisualization THEN
and out of the while this code:
tofRemotePanelUsage(IN:= xRemotePanelUsage, PT:=T#300MS);
That's my solution, I don't know how to do it with the methods.
Ok, now I know what you mean :-)
This will work for WebVisualization in general... When you have two active Visus and one is no longer active.... I think I need an Array to detect each Visu
for security i check the ip adress of the webvisu clients and only the known client is allowed to start special action and if this one get's lost, the process is stopped!
Hi dkugler, how did you manage to only allow certain IP addresses to start an action amongst other IP addresses?
OK. I Managed to use this code and it partly works. but I still have a problem:
Assuming operators devices loses the browser focus for some reason, the button stays pressed!
this is very dangerous. previous solution still recognize the client, but button will not stop the tap...
I set the variable of the button to false if Visu is not longer working.
But for that I need an Array if more Clients are active because with the code of dkugler you have allways active Visu if more clients are active.
I'm still testing this function... here my code till now. (Trigger if one client will become active or will lose connection)
Hope this will help you
This is inside of the while loop:
IF pClient^.GlobalData.ClientType=VU.Visu_Clienttype.WebVisualization THEN
Outside of while loop:
IF NOT TOF_Timeout.Q THEN
xVisuNotActive:=TRUE; //Diese Variable muss mit Steigender Flanke ausgewertet werden
IF TON_Reset.Q THEN
//Check if one Visu is no longer active
IF xCheckSameAgain THEN
IF (timLastWebVisuUsage[iSaveClientIdOfStopVisu] > timLastWebVisuUsage_old[iSaveClientIdOfStopVisu]) THEN
IF NOT xCheckSameAgain THEN
FOR i:=-1 TO 100 BY 1 DO
IF NOT (timLastWebVisuUsage[i]=T#0S) THEN
xWebVisuInUsage:=(timLastWebVisuUsage[i] > timLastWebVisuUsage_old[i]);
IF (timLastWebVisuUsage[i] <= timLastWebVisuUsage_old[i]) THEN
Just some uninformed two cents.
Why not hardwire this this functionality to a physical button instead..
Because I want to use a Button on my touch-Panel :-) => Sometimes not possible to Wire a Hardwire-Button
i use this solution only for not safety relevant functions! generally the hardwired estop is necessary! In my case the only client which is allowed to start/stop is a web panel from Berghof Automation with known ip. The browser app is the only active application and focus is fixed there, so i never had the problems like you. Only thing was, if network connection got lost. For checking and synchronising several modes, user login etc, i use a array of struct for each client and manage there the actual states. How to get the ip adress i found in the webvisu client example in the store. Search for a helper method/function. At thursday i will be back in the company. Then i'm able to take a code snipplet of that. I'll do a check, what happens if the button is pressed, connection get lost and comes up again. Because we use hybrid cabels with power and ethernet, the panel reboots. to test what happens if only ethernet get disconnected is a good question!
Yes thats true.. for safety functions you need a hardwired estop! In my case not necessary :-)
Because of IP-Adress...
Here I also postet a Project to download, where you can use the IP-Adress...try this.
Just because you can, doesn't mean that you should.
What damage (human, environment, product/machine) is to be expected when the button in question is NOT available while the button was pressed?
Thanks for the reply @dkugler, my problem is also relevant to @Iota application.
Our remote panels are for display purposes only, so how do I disable inputs from these WebVisu instances?
Sorry, I meant @Chris.O, my appologies
Just one Idea:
e.g. create an array xSwitchOn:ARRAY[-1..uiMaxNumbClients] of BOOL;
and with your Button switch "xSwitchOn[CurrentClientID]" to TRUE
Inside your programm you can Iterate over all Clients and see ClientID as well as the IP-Adress.
Make a For-loop (or inside the Iteration) and check if the "xSwitchOn" is TRUE and if IP-Adress is the same then your enabled one. Then set your "generalxSwitch" to TRUE... else set switch back to FALSE.
Just an Idea
@Chris.O: Alright that would work, but would be very tedious to set up for a large program. Also, it might be tricky to handle for Numpad inputs and such??
Is there a global variable available that disables all inputs coming from a specific IP address? This would be the ultimate solution.
I don't think so... but may be you can activate user management. You also can logout via IEC-Code.
So for Input in general you need then a User with password. If IP-Adress is "disabled" then log out this user automatically...
may be in that way...
That may be the way to go.
Could I limit the number of user logins to 1 at a time? Meaning, if I have one WebVisu instance open and am logged in as User1, then another person logs into a second instance of Webvisu as User2, User1 automatically gets logged out?
You can activate "CurrentVisu variables" inside the Viz-Manager (see Attached file)
Inside the Online-Help is written:
"The application recognizes and uses the global variable VisuElems.CurrentVisu of type STRING. It contains the name of the active visualization at application runtime.
In the application code, the variable can be read in order to retain the name of the active visualization. The variable can be written to for calling a switch of visualizations. The switch is done at the same time on all display devices.
Example: A TargetVisu display variant and several WebVisu display variants are active. When the CurrentVisu variable is written to, all display variants switch to this visualization.
Requirement: The application includes a visualization that calls other visualizations.
Assignment of variable: VisuElems.CurrentVisu := strVisuName;
Assignment of visualization name: VisuElems.CurrentVisu := 'visu1';"
May you can use this? I don't know how it works with different users.. I think ther is no influence on the users...
But I think you can do your wish on your own... you can also get the current logged in User for the different Clients with the Client iteration.
Then you can say if user is logged in twice, log out the old one...But I think it's a little bit of code :-)
Yes I am already using the CurrentVisu variable in my program, but it has no reference to the login. Basically all Webvisu and TargetVisu instances show the same visu at all times. If one visu changes, they all change.
I am looking for a way to limit the inputs to only one single visu instance, wether it would be a TargetVisu or a WebVisu.
I am thinking that I need to find a way to limit the number of simultaneous logins to 1 at a time. This would allow me to restrict input to one single screen and would be the easiest to implement.
Do you know of a variable that keeps track of user logins? For example, if user1 and user2 are logged in, then loginCount = 2...
You can Count it on your own.
Within this post I shared my Program (not the Code-Sniped, but the Project to download)
Here I Iterate all clients and read out some information. You can also geht som Usier-Info (Current logged In user for the different Clients)
So try e.g. If Current logged in user <> '' Then count+1
Or you use the code-sniped and use "pClient^.GlobalData.CurrentUserName" Inside the Iteration
If pClient^.GlobalData.CurrentUserName <> '' THEN
iCountUser:=iCountUser-1; //avoid to get a negativ value
Great, I will try and get this all put together before the end of the week and share my results in case anyone else has the same needs.
in this post https://forge.codesys.com/forge/talk/Deutsch/thread/91a22bbea1/#8506
you can find a project to login from IEC code. After creating two user groups in the usermanagement, maybe this is a other simple way to allow or disable user inputs on specific clients and visu objects. I can't use the currentvisuvariable in my project, so I login or out the right user during the iteration for synchronisation or check if the right user is logged in, as Chris.O described.
For those who suggest using hardwired buttons, it is not possible in my application. There are many "manual" buttons and our HMI should be mobile. You have to Walk around the site in order to operate different sections. It is not possible to put multiple panels around, because then we will need tens of them...
One of the reasons we have chosen Codesys for our application is the versatility and high end technology it introduce. I think that asking a button to stop operating in case of connection loss is mandatory. We achieve this with much much simpler HMIs easily.
In era where car drives themselves and robots are working next to humans, you can ask to operate a system with a touch screen button without being afraid it will get stuck...
May that will be a topic for the CoDeSys development to give a general solution without workaround like discussed here... May you should create a support-Ticket.
I have requested the improvement in our tracking database which already exists for the 3.5SP17 version.
because of little bit confusing discussions in this thread, if hints needed for the workarounds, let me know.
Has anyone been able to detect if web browser focus from a specific client has been lost?
We are currently trying to figure out how to detect if a webvisu is in focus or not on specific clients. Has anyone been able to make ground with this?
Any direction is appreciated.
I've searched for this too and wasn't able to find a usable value or bit. The only thing i can imagine is, that 3S has to enhance the webserver with such a function, because there are possibilities in HMTL and java to detect if the browser application with webvisu is in focus or not.
Yes we've come across the html/java methods as well. Do you know if it would be possible to run a html/java script internally or externally of the PLC that could detect the focus? Then we could make one of the variables accessible by a script inside the Codesys program?
sorry, I'm not familiar with html and java!
I really hope 3S will take care of this issue, as it seems to be a drawback for many users.
Meanwhile, my solution is a bit complicated but its the only one I could come up with:
I'm building an Android app with a webpage inside that runs the webvisu, and has a modbus server running, that keeps updating the PLC when the activity is in focus. Once the activity loses focus, the modbus stops shooting, and release every tap button that was pressed.
It is still in development, so I can't share it, but it's an idea for those who crave for solution...
I'm not sure if i understood your problem correctly... you want to know if a client opened a specific page?
For that I created a function which I called inside the Visualization inside a invisible dummy element.
Here you can e.g. call a function (e.g. for chage color...no matter) which is changing a bit of a global variable to TRUE.
Inside your code you can use this variable and set it back to FALSE. So every time when your visu is opended... your function inside this visu will set your bit to TRUE
Sure... for big projects you need a lot of variables => one for each page...but may you don't need it for every page
@Chris.O: how did you call a function from within the visualization without pressing a button?
I can't seem to get ST to execute without actually having a button pressed...
My idea would be to have a BLINK signal generated by the web server and have a button or element replicate this heart beat signal, which would tell me that at least one instance of this visualization is active and in focus...
You can call it like that (see attachment)
Inside this function you can do what ever you want...
(In this case the Function is of type BOOL)
Alright so I can call a function from the text variable field? Interesting...now what if I wanted a function to work as a heart beat to know if the visu is active and in focus?
My initial idea was to use a Blink signal to activate a button that would run some ST code. Once the visualization is no longer active, the ST code would stop running...
Is there anyway to force a click or tap of a button through ST code?
Why so complicated...
Inside your function you can run any code you want...
For example create a Global Variable for your Page and create a "BLINK" inside this function which turns on and off your global variable...
Then you can use this global Variable on any place of your Program...
Yes I understand, but this is the behaviour that I've seen in the past:
When I am on Visu1 with Button 1, and Button1_State = true, once I switch to another app of my android tablet, button remains true (Button1_State = true, not Button1_State = false)
Assuming my observation are correct, if Button1_State remains true, then my BLINK function won't stop running even though the user has navigated to another app on the tablet. My thought is by having an element on the screen that reflects the blink, then as soon as that visualization is no longer responding with a blink signal, I will know the user has navigated to another app.
This is a safety issue for us as all processes must stop if the user navigates away from the webvisu. So i am looking for a way to detect if we've navigated away from the visualization and onto another program.
Please correct me if I'm wrong or if you have a better way of achieving this.
But I think you can reset your Button1_State to false inside your Program right? So if you implement it in that way:
FUNCTION FUNPageActive : BOOL
IF NOT GVL.xVisuPageActive THEN
Will GVL.xVisuPageActive reset to false if the user navigates to another app on the tablet?
I don't know what exactly you do with your app...or if CoDeSys disconnect a Client...Try it!
You can also reset your button after a defined time... but if everything is fine you have to press again...
Sorry no other idea at the moment
Log in to post a comment.