YetAnotherForum
Welcome Guest Search | Active Topics | Log In | Register

How to build a framework for PI-ProcessBook Options · View
RJK Solutions
#1 Posted : Friday, July 18, 2008 9:23:24 AM
Rank: Administration

Groups: Administration

Joined: 6/20/2008
Posts: 458
Location: Cheshire, United Kingdom.
In the next series of posts I am going to show you how to build a framework that sits around PI-ProcessBook and performs common tasks and exposes your PI-ProcessBook displays to further functionality, functionality controlled by you.

Imagine that in a series of display files you want symbols on the display that are common to behave in the same way. For example, whenever someone clicks on a pbSymbolRectangle that the name begins with "SHOWHLP" (fullname "SHOWHLP_000012") you could display a message - the key to this being the unique id that follows "SHOWHLP" in the name; this could be a lookup to a data source for your help messages with an ID of "000012" or simply "12". You retrieve the content of the help message and display it to the user, but you don't want to write code for this in every display.


There are a number of ways you can do this.

The most complicated is to create a windows service that monitors for PI-ProcessBook usage and responds to the events (for those of you familiar with Visual Basic think "WithEvents" - C# think adding "EventHandler") that occur e.g. "Display_Open()", "Display_SelectionChange()". You can set it to montior multiple instances of PI-ProcessBook too. The downside to this is you will need the service installed and running on each of your clients.

Another option is to have a PI-ProcessBook display file that captures and handles the events as the services does, the benefit being the display file is already exposed to an instance of PI-ProcessBook to hook into the events. You need to ensure that any references to the application ("PBObjLib.Application") are not lost thus you will not get event notifications. With this approach to handling events, you do not rely on client software. If a client opens the displays from a central location the common code is handled centrally.

The final and most simple option is what I will describe to you over a series of post to this topic. It is similar in nature to the option above so all our common code will belong to a single display file but any other display wishing to be exposed to extra functionality must create a reference to the common display file. Once a reference is established to the common display events is the calling display need one line of code adding. Again, with this approach to handling events, you do not rely on client software. If a client opens the displays from a central location the common code is handled centrally.
If you set up a template display with the VBA code ready populated it minimises your effort for new displays.


Part 1 of building our framework will follow shortly, in the mean time familiarise yourself with the PI-ProcessBook VBA events, pbObjLib and pbSymLib. Any questions, commnets so far please post away.


OSIsoft PI System Specialists
PI consultancy on PI Systems, PISDK, AFSDK, OLEDB etc and PI custom developments. Well pretty much anything to do with PI!


Sponsor  
 
Guest
#2 Posted : Friday, July 18, 2008 3:29:09 PM
Rank: Guest
Groups:

Message was deleted by User.
RJK Solutions
#3 Posted : Friday, July 18, 2008 3:30:20 PM
Rank: Administration

Groups: Administration

Joined: 6/20/2008
Posts: 458
Location: Cheshire, United Kingdom.
Part 1: Simple "Hello World" common routine

Let us start by setting up our environment to work in. Create a folder and name it what you like, mine is called "Framework", this will be know as our working directory - we are going to put all our files in this same folder to keep things simple.

Next create a blank PI-ProcessBook display file and save it in your working directory as "myCommonRoutines.pdi".

Switch to the VBA Editor (Alt + F11) ensuring the Project Explorer is visible (Ctrl + R) and the properties window (F4).
Using the menu "Insert" add a new module and rename it to "RoutinesMain".
Inside this module we now want to add a common routine to handle the event that is triggered when a user selects a symbol, for this we are going to use the "Display_SelectionChange()" routine. So we shall add a Public sub routine called "Common_Display_SelectionChange()" to the module "RoutinesMain".
Select the "VBAProject" and rename that to "myCommonRoutines" - this avoids name conflicts when adding references.

As we want to know what PI-ProcessBook display file has called the routine, we need to pass the calling display as a parameter to the common routine.

Quote:
Public Sub Common_Display_SelectionChange(ByVal TheDisplay As Display)

End Sub


There are a couple of checks to perform before we start with any specific code:
- We only want to process this if PI-ProcessBook is in RunMode.
- We only want to process this for the last symbol selected (it is possible to select multiple symbols).
- We only want to process this if the last symbol selected is a Rectangle.
- We only want to process this if the Rectangle begins with "SHOWHLP".

Our routine now looks like the following:

Quote:
Public Sub Common_Display_SelectionChange(ByVal TheDisplay As Display)

If Not TheDisplay.Application.RunMode Then Exit Sub
If TheDisplay.SelectedSymbols.Count = 0 Then Exit Sub

Dim TheSymbol As Symbol
Set TheSymbol = TheDisplay.SelectedSymbols(TheDisplay.SelectedSymbols.Count)

If Not TheSymbol.Type = pbSymbolRectangle Then Exit Sub
If Not Left(LCase(TheSymbol.Name), 8) = "showhlp_" Then Exit Sub

End Sub


Please note, it is advisable to check the symbol name and then look up the appropriate routine to call. For this example we will simplify this by only processing one symbol type/name combination.

Now that we have our checks in place we can parse the symbol and we will display the help message number contained in the name of the symbol. In reality, this is the point we would perform a lookup on our data store for the relevant information.

To display the message is easy and can be done on one line:

Quote:
Public Sub Common_Display_SelectionChange(ByVal TheDisplay As Display)

If Not TheDisplay.Application.RunMode Then Exit Sub
If TheDisplay.SelectedSymbols.Count = 0 Then Exit Sub

Dim TheSymbol As Symbol
Set TheSymbol = TheDisplay.SelectedSymbols(TheDisplay.SelectedSymbols.Count)

If Not TheSymbol.Type = pbSymbolRectangle Then Exit Sub
If Not Left(LCase(TheSymbol.Name), 8) = "showhlp_" Then Exit Sub

Call MsgBox("Show help message called. The ID = " & CStr(Split(TheSymbol.Name, "_")(1)))

End Sub


Save your common routines display!

I have purposely excluded any error handling for this example to prevent confusion with the simplistic code that gives such big benefits.

So any PI-ProcessBook display file can call this routine to check for matching symbols and display the message.
Create a new blank display file in your working directory and name it "ExampleFile1.pdi".

The trick to exposing the functionality from common routines is to add a reference to "myCommonRoutines.pdi". To do this go to the VBA editor (Alt + F11) and select the "Tools" menu option followed by references. From the references window select the "Browse" button and go to your working directory to select "myCommonRoutines.pdi". When browsing ensure your "File Type" is set to "Display Files (*.pdi)"

Now that your reference is set there is 1 last step to perform, adding the call to the common routine.
In the VBA Explorer double click on "ThisDisplay" for "ExampleFile1.pdi". Next, in the object dropdown list select "Display" followed by "SelectionChange" in the list of events.
you should now see the following in your VBA editor:

Quote:
Private Sub Display_SelectionChange()

End Sub


Now you add in 1 line of code and you are done.

Quote:
Private Sub Display_SelectionChange()
Call Common_Display_SelectionChange(ThisDisplay)
End Sub


Now whenever a symbol is selected in your display the common routine is called.
If you now treat this display as a template you will not need to repeat the steps above for each new display.

Save "ExampleDisplay1.pdi".

Go to the display build page and add a circle and a rectangle to your display whilst in build mode.
Name the Circle "SHOWHLP_0001" and name the Rectangle "SHOWHLP_0002" and select Run mode.

Now when you click on the circle nothing happens but when you click on the Rectangle you will see the message "Show help message called. The ID = 0002".

Hopefully by this point you start to see the power of a common display and the possibilities for common routines to be applied to all displays. You can add any number of Rectangles name "SHOWHLP_xxxx" and the same code is executed each time.

In the next part we will look into something a bit more complex by expanding the SelectionChanged common routine to perform a routine lookup based on the symbol name/type.


OSIsoft PI System Specialists
PI consultancy on PI Systems, PISDK, AFSDK, OLEDB etc and PI custom developments. Well pretty much anything to do with PI!


milesUK
#4 Posted : Thursday, January 21, 2010 3:50:45 PM
Rank: Member
Groups: Member

Joined: 5/28/2009
Posts: 18
Location: Cheshire, UK
Rhys, thank you for an excellent introduction. I have combined this with your other how-to article "Change time range of all Trends on a display" but intend to extend it further to add code to standrdise the look of my main ProcessBook's displays.

I am currently having to place the 'Display_SelectionChange()' code and the Reference to the common routines for every ProcessBook Entry.

Can anyone point me in the right direction to make this common at the WorkBook level? I do intend to automate my Displays when I can figure out how to do it but in the meantime I'm stuck with an awful lot of ProcessBook entries.

Regards,

Miles
Michael
#5 Posted : Thursday, January 21, 2010 9:09:07 PM
Rank: Advanced Member
Groups: Member

Joined: 12/3/2009
Posts: 71
Location: Germany/Pennsylvania
Miles,
The best way is to create a PI-Processbook add-in. Then you will have the functionality available in all your displays. But you need a VB compiler. An old VB6 is still fine, particularly if are used to VBA and not DOTNET.
Developing an add-in is not difficult, but you should have some experience with VB (no matter what version).

But let us wait and see what Rhys is planning for the next lessons (Maybe it is already on his list).

Michael
RJK Solutions
#6 Posted : Thursday, January 21, 2010 9:42:41 PM
Rank: Administration

Groups: Administration

Joined: 6/20/2008
Posts: 458
Location: Cheshire, United Kingdom.
Hi Miles...welcome back BigGrin

Right there are 2 sides to this, firstly Michael is right in the world without restrictions then ProcessBook add-ins give you so much more control at the Application object level. On the other side there is always the issue of distributing the add-ins, registration in a lockdown client environment - plus you need some skillz in .Net. It is a lot easier (and quicker IMO) to distribute a common display with associated displays on a file share.

What I did to make life easier was to create a little executable that actually adds all the required VBA event signatures, common routines to call and adds the reference. So I never really wrote any VBA, just let the executable write the code via VBE. Still works today for a client 5 years on since I wrote it!
It is actually relatively straightforward to code, so let me dig it out when I am back at my development systems...you can even expand this to add objects to your display automatically, I made it add links to other displays that track which displays are used etc and it helped to build about 2,000 displays with getting RSI.

Maybe I should revive this topic a bit more...if I ever get a spare minute Razz


OSIsoft PI System Specialists
PI consultancy on PI Systems, PISDK, AFSDK, OLEDB etc and PI custom developments. Well pretty much anything to do with PI!


Michael
#7 Posted : Friday, January 22, 2010 1:32:34 PM
Rank: Advanced Member
Groups: Member

Joined: 12/3/2009
Posts: 71
Location: Germany/Pennsylvania
You are right; this is the smartest way if you have a central managed system of displays.

I did such a solution to simplify display navigation 10 years ago for a collection of 1000 displays and it is still in use.

[5 years x 2000 displays = 10 years x 1000 displays :-)] Today I would create the same system.

Nevertheless, an add-in gives you more functionality. Unfortunately most of the features I added to my add-in are obsolete now because OSISoft included them in ProcBook (recent display list, a calendar etc, but some not like “Automatic Fit All”, shortcut to Trend.SetMultiScale)
milesUK
#8 Posted : Friday, January 22, 2010 3:49:39 PM
Rank: Member
Groups: Member

Joined: 5/28/2009
Posts: 18
Location: Cheshire, UK
Micheal/Rhys, Thankyou both. I have written VB but more than 10 years ago now (Y2K upgrade) and I have wanted to move some of my functions/procedures into an Excel Add-In but never seem to be able find enough time to tackle it knowing only to well that in the long run it should help.

With 1000 & 2000 displays you are both well over my modest 100+.

Our client environment IS locked down but I am sure than Add-In could be distributed.

Unlitimately I hope to have a ProcessBook to access all of our transfomer loading data (almost 800 units with an average of a dozen tags on each site) I was hoping to use the MDB (or AF in the distant future) to allow the user to select a module and then have PB automatically build the display and then probably throw it away afterwards. Our tag names are nicely descriptive (location~circuit~name~units) as is the proposed MDB (based on those same location names).

For now though the framework and time range are already proving useful and productive as I am now defaulting my displays to [*-1h,*] instead of [*-7d,*] previous to today.

Regards,

Miles
RJK Solutions
#9 Posted : Friday, January 22, 2010 4:50:26 PM
Rank: Administration

Groups: Administration

Joined: 6/20/2008
Posts: 458
Location: Cheshire, United Kingdom.
Miles, to answer the AF part of your post...then if you can template a display to represent equipment then you can use ERD (Element Relative Displays) to navigate amongst your equipment. I hear OSI are looking in to this part of AF/ERD/ProcessBook displays to make it "easier" for users.

I have some displays that store configuration data in PI-MDB so when displays load, they load the data to customise the display. Works great and you can use it from VBA. With AF v2.x you don't get the type libraries so you won't be able to access AF via VBA, you need a .Net addin for that.


OSIsoft PI System Specialists
PI consultancy on PI Systems, PISDK, AFSDK, OLEDB etc and PI custom developments. Well pretty much anything to do with PI!


Big
#10 Posted : Thursday, February 11, 2010 6:03:55 PM
Rank: Member
Groups: Member

Joined: 1/19/2010
Posts: 11
Location: Baton Rouge
If I'm understanding this correctly, making my own dll or using this framework method are the only routes for me to share code between displays, even if all the displays are located in the same processbook?

What is the purpose of the Class Modules in the displays if I cannot have them easily shared between every display in a processbook?
milesUK
#11 Posted : Thursday, May 13, 2010 11:56:24 AM
Rank: Member
Groups: Member

Joined: 5/28/2009
Posts: 18
Location: Cheshire, UK
I short while ago I used this article by Rhys to easily change time ranges with a simple click of the mouse.

As I had many (100+) existing displays I therefore had the repetitive task of adding the required symbols and references to the common display file for each and every display. Any future additions would have to be made to each display again. I did not have the knowledge to create code to add the code as Rhys could.

I also had relative few time ranges that I wanted to choose from and I really wanted buttons on the toolbar that would be available to every display I used. I then read this article on building a framework and put the following together.

Each button I add to the toolbar must first have it's own subroutine created but this is fairly simple. For example the one immediatly below gives a 12 hour time range:

Code:
Public Sub Switch_Trend_Range_12h()

    Dim active_disp As Display, my_hours As Integer
   
    Set active_disp = Application.ActiveDisplay
   
    my_hours = 12
   
    If Not (active_disp Is Nothing) Then
   
        Call Switch_Trend_Range(active_disp, my_hours)
       
        Set active_disp = Nothing
       
    End If

End Sub


This one is from Rhys' framework but modified:

Code:
Public Sub Switch_Trend_Range(ByVal TheDisplay As Display, ByVal iHours As Integer)

Dim sym As Symbol
Dim e As TrendElement

    If TheDisplay.Symbols.Count > 0 Then
   
        For Each sym In TheDisplay.Symbols
       
            If sym.Type = pbSymbolTrend Then
              Call sym.SetTimeRange("*-" & iHours & "h", "*") 'set TEMPORARY time range
            End If
           
        Next sym
       
    End If
   
    Set TF = Nothing
End Sub


and a second one to apply standard format:

Code:
Public Sub Standard_Format(ByVal TheDisplay As Display, ByVal iHours As Integer)

Dim sym As Symbol
Dim e As TrendElement
Dim TheTrend As Trend
'Dim tp As Symbol
Dim TF As TrendFormat

    If TheDisplay.Symbols.Count > 0 Then
        For Each sym In TheDisplay.Symbols
            If sym.Type = pbSymbolTrend Then
   
                Call sym.SetStartAndEndTime("*-1h", "*") 'set PERMANENT time range to 1h so that opening large displays is quick
                   sym.Height = 361
                    sym.Width = 381
   
                'standardise styles
                    Set TheTrend = sym '
       
                    Set TF = TheTrend.GetFormat
                    TF.Elements(pbBackGround).Color = pbBlack
                    TF.Elements(pbHAxis).Color = RGB(100, 100, 100)
                    TF.Elements(pbVAxis).Color = RGB(100, 100, 100)
                    TF.Elements(pbText).Color = RGB(150, 150, 150)
       
                    With TF
                        .DisplayScaleInside = False
                        .ShowDescription = False
                        .ShowEngUnits = True
                        .ShowGrids = False
                        .ShowTagName = True
                        .ShowTitle = True
                        .ShowTraceMarkers = False
                        .ShowValue = False
                    End With
       
                    With TF.Elements(pbPen1)
                        .Color = pbRed
                        .LineStyle = pbLSolid
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
                    With TF.Elements(pbPen2)
                        .Color = pbYellow
                        .LineStyle = pbLSolid
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
                    With TF.Elements(pbPen3)
                        .Color = pbBlue
                        .LineStyle = pbLSolid
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
                    With TF.Elements(pbPen4)
                        .Color = pbGreen
                        .LineStyle = pbLSolid
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
                    With TF.Elements(pbPen5)
                        .Color = pbRed
                        .LineStyle = pbLDot
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
                    With TF.Elements(pbPen6)
                        .Color = pbYellow
                        .LineStyle = pbLDot
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
                    With TF.Elements(pbPen7)
                        .Color = pbBlue
                        .LineStyle = pbLDot
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
                    With TF.Elements(pbPen8)
                        .Color = pbGreen
                        .LineStyle = pbLDot
                        .LineWidth = pbThin
                        .MarkerStyle = pbCCircle
                    End With
               
                    TheTrend.SetFormat TF 'update the trend’s format definition and repaint the trend
               
            End If
        Next sym
    End If
    Set TF = Nothing
    Set TheTrend = Nothing
End Sub


The above routines reside in Modules. Next add the button(s) to the toolbar or menu bar:

Customise the Toolbars (right-mouse-click on toolbar) and select the Commands tab in the Customize dialogue box.

Choose the "User Definable" Category. Click the "+" next to Macros until you find the required macro. Drag the macro entry to the toolbar. Right-mouse-click on the new toolbar item to customise that.

Does not require References to be made to the common sheet. Job done. If you place the buttons in the Menu bar they won't appear until you actually Open a display (at least that's the behaviour on my PC!). Apologies for any crude code - as a non-professional programmer I would not know crude code if it crashed and smacked me in the face with a Erro dialogue box!

Miles
RJK Solutions
#12 Posted : Friday, May 14, 2010 3:02:50 PM
Rank: Administration

Groups: Administration

Joined: 6/20/2008
Posts: 458
Location: Cheshire, United Kingdom.
Hi Miles,

Thanks for sharing!
As an additional hint, you can control the toolbars programatically too...look at PBCommandBar in the ProcessBook VB help file. So you "could" add a routine to your central display to create the PBCommand bar if it doesn't exist and link up the routines to the buttons, users would then just open the display and everything magically appears. BigGrin




OSIsoft PI System Specialists
PI consultancy on PI Systems, PISDK, AFSDK, OLEDB etc and PI custom developments. Well pretty much anything to do with PI!


milesUK
#13 Posted : Monday, May 17, 2010 4:02:42 PM
Rank: Member
Groups: Member

Joined: 5/28/2009
Posts: 18
Location: Cheshire, UK
Rhys, automation! I love it.

Thanks for heads-up on that - as a hobby programmer I don't automatically know what is out there that can help me. My day job gets in the way of research. BigGrin

Cheers

Miles
Users browsing this topic
Guest (2)
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.