Refresh WebVisu Client through FBChangeVisu

rckalex
2021-03-23
2021-03-29
  • rckalex

    rckalex - 2021-03-23

    It appears that if a WebVisu keeps the same page up for a number of days it will eventually "lose" some of the page's elements. I have not figured out if the root problem is with the Codesys Visualization or with the Chrome browser. For this reason I am looking for a way to trigger a refresh of a webvisu client if the WebVisu hasn't been navigated away from for some period of time.

    If it possible to have the FBChangeVisu function (https://help.codesys.com/webapp/t6Wggu4AU17ivuxOCz5MhwO5thc%2FFbChangeVisu;product=VisuUtils;version=3.5.12.0) reference the "CurrentVisuName" parameter of the current client as it works through the client filter?

    Is there a better way to cause a refresh of the WebVisu on a timer?

     
    • m.prestel

      m.prestel - 2021-03-24

      It would be best if you are able to reproduce the issue and then report it!

       
      • rckalex

        rckalex - 2021-03-24

        Marcel,

        I'll check to see if the behavior is browser agnostic and then report if necessary. In the interim there is an issue that I need to work around. Is there a way to reference the "CurrentVisuName" parameter of the current client as it works through the client filter (VU.IVisualizationClientFilter)?

         
        • m.prestel

          m.prestel - 2021-03-25

          Implement your own IVisualizationClientFilter.
          Accept will be called with IVisualizationClient, which contains the property CurrentVisuName

           
  • rickj

    rickj - 2021-03-24

    Here is a snippet of my code used for an "auto return to home screen" function. It's based off the codesys "Key Switch Login" example project which is also attached. It's a bit challenging in that there is no session execution context making it necessary to first get a reference to the session, which is more complicated than necessary and sparsely documented IMHO.

        VisuClient : POINTER TO VisuElems.VisuStructClientData;
    
        // Iterate over all currently active target visualization clients 
        // IMPORTANT: This must be done only from the VISU-TASK!!!
        VisuElems.g_ClientManager.BeginIteration();
        WHILE (VisuClient := VisuElems.g_ClientManager.GetNextClient()) <> 0 DO
            IF (VisuClient^.GlobalData.ClientType = VisuElems.Visu_ClientType.TargetVisualization)  THEN
                VisuElems.g_VisuManager.SetMainVisu(VisuClient,'ScreenName');
            END_IF
        END_WHILE
    
        // Iterate over all currently active web visualization clients
        // IMPORTANT: This must be done only from the VISU-TASK!!!
        VisuElems.g_ClientManager.BeginIteration();
        WHILE (VisuClient := VisuElems.g_ClientManager.GetNextClient()) <> 0 DO
            IF NOT (VisuClient^.GlobalData.ClientType <> VisuElems.Visu_ClientType.TargetVisualization)  THEN
                VisuElems.g_VisuManager.SetMainVisu(VisuClient,'ScreenName'); 
            END_IF
        END_WHILE
    
     
    • m.prestel

      m.prestel - 2021-03-24

      Please use the visu utils and not .BeginIteration()

       
      • rckalex

        rckalex - 2021-03-24

        Marcel,

        Is the official stance to no longer use the method proposed by Rick/illustrated in the sample? Is there a sample project you could point me towards that accomplishes the same using visu utils?

         
        • m.prestel

          m.prestel - 2021-03-25

          GetNextClient will produce a warning starting with SP17.

          The problem is simple, most of the users access visu data outside of the visu task resulting in possible crashes.

           
        • m.prestel

          m.prestel - 2021-03-25
          PROGRAM PLC_PRG
          VAR
              changeVisu : VU.FbChangeVisu;
              xExecute: BOOL;
              eError: VU.ERROR;
              xError: BOOL;
              xBusy : BOOL;
              xDone: BOOL;
              itfClientFilter: VU.IVisualizationClientFilter := VU.Globals.AllClients;
          END_VAR
          ----
          changeVisu(itfClientFilter := itfClientFilter, eError => eError, xExecute := xExecute, xDone=>xDone, xBusy=>xBusy, xError=>xError, sVisuName := 'Screen');
          
           
          • rckalex

            rckalex - 2021-03-25

            Marcel,

            As written it will refresh any client on that visualization page not just one with an extended duration. I would have to have a different custom filter for every visualization in the project. Prior to posting my question I already had a customer VisuClientIteration and ClientFilter based on your recommendation in this thread (https://forge.codesys.com/forge/talk/Deutsch/thread/f14041c158/?limit=25#9c5f).

            Do you see any issue with implementing the custom Iteration with the HandleClient method doing the refresh?

            FUNCTION_BLOCK VisuClientIteration IMPLEMENTS VU.IVisualizationClientIteration
            VAR_INPUT
            END_VAR
            VAR_OUTPUT
            END_VAR
            VAR 
                fbVisuRefresh   : VU.FbChangeVisu;
                fbClientRefreshFilter : ClientFilterRefreshScreen;
                fbTargetedClientFilter : ClientFilterTargeted;
                xRefreshDone    : BOOL;
                eRefreshError   :  VU.ERROR;
                xRefreshBusy    : BOOL;
                xRefreshError   : BOOL;
            
            END_VAR
            
            ------------------------------------
            
            GVL.iNumberOfClients:=GVL.iNumberOfClients+1;
            
                GVL.aStClientInfo[itfClient.ClientId].iClientID := itfClient.ClientId;
                IF GVL.aStClientInfo[itfClient.ClientId].stCurrentVisu <> itfClient.CurrentVisuName THEN
                    GVL.aStClientInfo[itfClient.ClientId].timeLastScreenChange := GVL.dwNow;
                END_IF
                GVL.aStClientInfo[itfClient.ClientId].stCurrentVisu := itfClient.CurrentVisuName;
                GVL.aStClientInfo[itfClient.ClientId].wsUserName := itfClient.UserName;
                GVL.aStClientInfo[itfClient.ClientId].sIpAddress := itfClient.GetIPv4Address();
                GVL.aStClientInfo[itfClient.ClientId].ClientType := itfClient.ClientType;
                GVL.aStClientInfo[itfClient.ClientId].timeLastActive := GVL.dwNow;
            
                IF GVL.aStClientInfo[itfClient.ClientId].timeLastScreenChange < (GVL.dwNow - GVL.dwScreenRefreshDuration) THEN
                    gvl.iClientToRefresh := itfClient.ClientId;
                    fbVisuRefresh(itfclientFilter := fbTargetedClientFilter, eError => eRefreshError, xExecute := TRUE, xDone => xRefreshDone, xError => xRefreshError, xBusy => xRefreshBusy, sVisuName := itfClient.CurrentVisuName);
                END_IF
            

            In this case the IsAccepted method of the ClientFilterTargeted is checking

            IF itfClient.ClientId = gvl.iClientToRefresh THEN
                IsAccepted := TRUE;
            END_IF
            
             
            • m.prestel

              m.prestel - 2021-03-29

              Again it would be way better for you to reproduce and report the issue.

               
          • rickj

            rickj - 2021-03-27

            Thanks Marcel and rckalex for all the info.

            Marcel, Just wondering, wouldn't all this be much easier to do if one could attach code at session/client, screen, and element levels as many other HMI systems do. For example, to create a client timeout one would just put a timer and a change screen command in a program having context/scope within a client. Same for screens and for elements.

            It would make all the "not calling from visu task crashes" go away, would it not?

            Anyway thank you for the help it is so much appreciated.

            Rick

             

            Last edit: rickj 2021-03-27
            • m.prestel

              m.prestel - 2021-03-29

              The solution CODESYS followed was to use the common behavior model and do it this way.

              In general I personally think that if you can get the instance path to a variable, someone will simply read/write to it, because it is a quick solution.
              Most people are not aware of multi tasking/threading issues.

              Best regards,
              Marcel

               
  • rickj

    rickj - 2021-03-25

    Yes, examples would be very helpful.

     

Log in to post a comment.