• Not Answered

Total views and time spent viewing individual displays

Hi everyone! 

Is there a way to find out how many times individual displays are selected and how long the display remains open for viewing per workstation for a defined time period?

The thought is that it may be helpful to know those statistics when beginning efforts to create useful level 2 displays, minimizing the number of displays, transitioning to live, etc.

 

Thanks!

Jenny

12 Replies

  • Yes this can be done, this will get you on the way:

    1. Right click on User under Globals in Operate System Tree and Create a variable named “gs_OpenPictures”
    2. Right click on the variable and configure the variable property VariableType to be 8 - vtString
    3. Right click on the variable and choose:
      1. Animations
      2. Select the Variable tab
      3. Check animate of CurrentValue
      4. Select “Format” for the CurrentValue Data Conversion
      5.  Add the following to the Data Source box: “frsVariables.main_glb.gs_mainCurrent.CurrentValue + frsVariables.main_glb.gs_mainCurrent2.CurrentValue + frsVariables.main_glb.gs_mainCurrent3.CurrentValue + frsVariables.main_glb.gs_mainCurrent4.CurrentValue”
      6. Click OK to close the dialog box
    4. Right click on User and select Edit Script
    5. Paste the below logic right below the "Option Explicit" at the very top of Project_User - User (Code)

    Public Display1 As String
    Public Display2 As String
    Public Display3 As String
    Public Display4 As String 

    Private Sub gs_OpenPictures_OnChange()
    Dim strDisplay As String
    Dim DisplayChange As Boolean 

    On Error GoTo ErrorHandler
        strDisplay = Trim(frsVariables.gs_mainCurrent.CurrentValue)
        If IsEmpty(strDisplay) = False And _
           StrComp(strDisplay, "") <> 0 And _
           StrComp(strDisplay, "EMPTY") <> 0 Then
            Display1 = strDisplay
            DisplayChange = True
        End If
       
        strDisplay = Trim(frsVariables.gs_mainCurrent2.CurrentValue)
        If IsEmpty(strDisplay) = False And _
           StrComp(strDisplay, "") <> 0 And _
           StrComp(strDisplay, "EMPTY") <> 0 Then
            Display2 = strDisplay
            DisplayChange = True
        End If
       
        strDisplay = Trim(frsVariables.gs_mainCurrent3.CurrentValue)
        If IsEmpty(strDisplay) = False And _
           StrComp(strDisplay, "") <> 0 And _
           StrComp(strDisplay, "EMPTY") <> 0 Then
            Display3 = strDisplay
            DisplayChange = True
        End If
       
        strDisplay = Trim(frsVariables.gs_mainCurrent4.CurrentValue)
        If IsEmpty(strDisplay) = False And _
           StrComp(strDisplay, "") <> 0 And _
           StrComp(strDisplay, "EMPTY") <> 0 Then
            Display4 = strDisplay
            DisplayChange = True
        End If
        If DisplayChange = True Then
            'This is where your logic would go to save the time, and displays
            '"Now" will give you a timestamp
            'frsVariables.gs_wsName.CurrentValue will give you the workstation name as you will want to include this and maybe use this for filename for your data

        End If
        Exit Sub

    ErrorHandler:
        HandleError
    End Sub

    Do you have an Emerson or Emerson Impact Partner office/person that supports you?

  • In reply to Matt Stoner:

    Thank you for your reply. I will give your suggest a try :)

    Yes, we have an Emerson Impact Partner. I had not thought of reaching out to our Impact Partner with this question.

    Jenny
  • In reply to Jenny La Bounty:

    If they are onsite, Have them contact me as there is probably something else we can do.
  • In reply to Matt Stoner:

    Unfortunately, no, the Impact Partner is not onsite. I can reach out to them to see if they have any suggestions.
  • In reply to Matt Stoner:

    Emerson has created a utility for Operate to log display callup as a tool to evaluate HMI performance for the purpose of improving the HMI on DeltaV Live migrations. As you mention, understanding how and when, or if never, a display is used is useful for driving change.

    The tool saves the information to a log file created on the workstation.

    There is no tool to monitor DeltaV Live display callups. I think there should be as ongoing improvements can be made if we realize how our Operators execute their work.

    In any case, I thought about using a Control Module to record Display activity. When a display is called up, if we write the name of the display to a module (can be on an app station or Pro Plus), the Write action will generate an Ejournal Parameter Change record, with Time stamp, Node, User and the new value. If you create a Main1, Main2, User1, User2 string parameter in the module, and write the display name of the corresponding location, you can use the Ejournal to track these activity, and quickly filter on Node to see the new displays being called, as well as who was logged on.

    This would work for both Operate and Live. Except Live is currently lacking a way to read which displays are open in various display frames, or for a Display to know what Display frame it is open in. But that is for a different thread.

    Using Matt's approach, you would write by exception (only when the display changes) to the Display Tracking module and that automatically creates the ejournal entry. Some filtered PHV views would give you the insight you're looking for.

    Adding display navigation events to the Ejournal might not be desirable if the system is dealing with large number of events and such. a dedicated Ejournal could be added for this purpose. Keep this module in its own Plant Area and assign only that area to the Ejournal for a focused collection of HMI activities. Maybe hardware alerts and such are targeted to this "support" ejournal leaving the Operator focused Ejournal for control module alarms and events.

    Andre Dicaire

  • In reply to Andre Dicaire:

    Thank Andre! I will look into the tool as the two units that we are interested in evaluating are both using Operate and in the meantime will pursue Matt's suggestion as well. Our smaller units are using Live but they have few displays.
  • In reply to Andre Dicaire:

    Andre, is the Emerson utility for Operate available to the general population? We've done some work on several DCS vendors to document which graphic displays are being used and how much in preparation for major graphic projects where it is a DCS migration, change to new graphics platform like Live, or an HP HMI effort. Looking into solutions for Operate has been on my to do list for a while. I can try Matt's suggestion, but also curious about the utility you mentioned.
  • In reply to Michael Moody:

    I will direct you to your Local Impact partner. I think we only provide this to customers in the context of a migration to live scope of work evaluation. It is not a hotfix per se. Matt has provided the core functionality in his post.

    Andre Dicaire

  • adding on to what and have supplied here is a version that writes to csv (broken into multiple posts as there seems to be a hidden limit)

    Private Sub gs_OpenPictures_OnChange()
    '==========================================================================================================================
    'Triggered when any of teh gs_mainCurrent variables change in Operate
    'Checks each of the 4 display variables and logs if the value changed
    '==========================================================================================================================
    'Declare Variables
    Dim strDisplay As String
    Dim prevDisplay As String

    'Error Handling
    On Error GoTo ErrorHandler

    '---Display 1---
    'Read current value from Operate variable
    strDisplay = Trim(frsVariables.gs_mainCurrent.CurrentValue)
    'main_glb.gs_mainCurrent.CurrentValue


    'Validate that we have a display name and that it is not empty
    If IsEmpty(strDisplay) = False And _
    StrComp(strDisplay, "") <> 0 And _
    StrComp(strDisplay, "EMPTY") <> 0 Then
    'store previous value to compare
    prevDisplay = Display1
    Display1 = strDisplay

    'Only log if the display actually chnages
    If StrComp(prevDisplay, Display1) <> 0 Then
    LogDisplayChange 1, Display1
    End If
    End If

    '---Display 2---
    'Read current value from Operate variable
    strDisplay = Trim(frsVariables.gs_mainCurrent2.CurrentValue)

    If IsEmpty(strDisplay) = False And _
    StrComp(strDisplay, "") <> 0 And _
    StrComp(strDisplay, "EMPTY") <> 0 Then
    prevDisplay = Display2
    Display2 = strDisplay

    If StrComp(prevDisplay, Display2) <> 0 Then
    LogDisplayChange 2, Display2
    End If
    End If

    '---Display 3---
    'Read current value from Operate variable
    strDisplay = Trim(frsVariables.gs_mainCurrent3.CurrentValue)

    If IsEmpty(strDisplay) = False And _
    StrComp(strDisplay, "") <> 0 And _
    StrComp(strDisplay, "EMPTY") <> 0 Then
    prevDisplay = Display3
    Display3 = strDisplay
    If StrComp(prevDisplay, Display3) <> 0 Then
    LogDisplayChange 3, Display3
    End If
    End If


    '---Display 4---
    'Read current value from Operate variable
    strDisplay = Trim(frsVariables.gs_mainCurrent4.CurrentValue)

    If IsEmpty(strDisplay) = False And _
    StrComp(strDisplay, "") <> 0 And _
    StrComp(strDisplay, "EMPTY") <> 0 Then
    prevDisplay = Display4
    Display4 = strDisplay
    If StrComp(prevDisplay, Display4) <> 0 Then
    LogDisplayChange 4, Display4
    End If
    End If

    Exit Sub
    ErrorHandler:
    HandleError
    End Sub
  • post 2

    Private Sub EnsureFolderExists(folderPath As String)
    'creates a folder if it does not already exist using File System Object
    'ensure that the folder directory defined as a constant contains the trailing \
    'you can add a reference for Microsoft Scripting Runtime, but the late binding works by setting fso = Scripting.FileSystemObject

    'decalre variables
    Dim fso As Object

    On Error Resume Next

    'check if the folder already exists using Dir
    If Dir(folderPath, vbDirectory) = "" Then
    'Create FileSystemObject Instance (late binding)
    Set fso = CreateObject("Scripting.FileSystemObject")
    If Not fso.FolderExists(folderPath) Then
    fso.CreateFolder folderPath
    End If
    'clean up Object Reference
    Set fso = Nothing
    End If

    On Error GoTo 0
    End Sub

    Private Function BuildLogFilePath(wsName As String, displayNumber As Integer) As String
    'builds the full path for a log file based on the configuration

    'Parameters:
    'wsName - Workstation Name (used for file name)
    'displayNumber - Display number 1-4

    Returns:
    'Full path to log file

    'declare variables
    Dim folderPath As String
    Dim fileName As String
    Dim dateStamp As String
    Dim monthFolder As String

    'determine what file structure to use based on user choice
    If USE_DAILY_FILES Then
    'build the monthly folder name (adjust if needed)
    monthFolder = Format(Now, "yyyy-mm")
    'set the date stamp, can change the format if you want
    dateStamp = Format(Now, "yyyy-mm-dd")

    folderPath = LOG_FOLDER_PATH & monthFolder & "\"
    'check to make sure folder(s) exists
    EnsureFolderExists LOG_FOLDER_PATH
    EnsureFolderExists folderPath

    'build the file name, change here if you want to append anything to the name or change it
    fileName = wsName & "_Display" & displayNumber & "_" & dateStamp & ".csv"
    BuildLogFilePath = folderPath & fileName
    Else
    EnsureFolderExists LOG_FOLDER_PATH

    fileName = wsName & "_Display" & displayNumber & "_Log.csv"
    BuildLogFilePath = LOG_FOLDER_PATH & fileName
    End If
    End Function

    Private Sub LogDisplayChange(displayNumber As Integer, graphicName As String)
    'writes a display change to the log file, appends data in the next available row


    'decalre variables
    Dim filePath As String
    Dim fileNum As Integer
    Dim wsName As String
    Dim fileExists As Boolean

    'error handler
    On Error GoTo LogErrorHandler

    'get the workstation name - add anyting else here that you may want in the csv such as current user etc.
    wsName = frsVariables.gs_wsName.CurrentValue
    'build the file based on the configured settings
    filePath = BuildLogFilePath(wsName, displayNumber)

    'check if the file exists to determine if it is a new file, and if it is then write the header, dont if the file exists
    fileExists = (Dir(filePath) <> "")

    'get the file handle, if the file is open it will not write, but will not break either
    fileNum = FreeFile
    'open the file to append, the Open command is what is also used to create the file if it does not exist
    Open filePath For Append As #fileNum

    'write header if it is a new file
    If Not fileExists Then
    Print #fileNum, "DateTime,Workstation,DisplayNumber,GraphicName" 'this sets the header in the sheet, add to it if you want to track more information e.g. current user
    End If

    'append to the next row
    Print #fileNum, Format(Now, "yyyy-mm-dd hh:nn:ss") & "," & wsName & "," & displayNumber & "," & graphicName 'if you add to header, also add the data here to be written

    Close #fileNum

    Exit Sub
    LogErrorHandler:
    If fileNum > 0 Then Close #fileNum
    End Sub
  • In reply to Benji_Kidmose:

    Thank you for sharing! The help is much appreciated.
  • In reply to Jenny La Bounty:

    there is a bit of the code missing, having issues posting, get a lot of errors, will try to get updated