15
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577 Page 1 General PI SDK Programming and Best Practices

General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

  • Upload
    others

  • View
    30

  • Download
    0

Embed Size (px)

Citation preview

Page 1: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 1

 

   

General PI SDK Programming and Best Practices

Page 2: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 2

 

1.1 General PI SDK Programming and Best Practices

1.1.1 Objectives

At the end of this learning lab, you should be able to:

• Establish a connection to a PI server; • Close a connection to a PI server; • Display the Connection Manager; • Retrieve tags that correspond to a tag mask; • Retrieve tags using the Tag Search window; • Use the PointList collection; • Display the properties of a PI point via a custom list; • Display the properties of a PI point via the Point Attributes window; • Modify the value of a point’s properties; • Add a PI point; • Read the snapshot value of a PIPoint object; • Read archived PI values; • Work with the PIValues collection.

Abstract

PI SDK is a proprietary low-level technology. It can be used under the form of a library included to a Visual Studio project for example. The PI SDK library allows managing or finding PI Points, reading and writing data, performing calculations, making use of common dialog windows and much more.

1.1.2 Problem Description

You are a new developer hired for a company that employs many PI Servers; you need to develop an application requiring many PI Servers. The end-user will need to retrieve points based on a tag mask or use the Tag Search dialog box. The application must allow end-user to modify PI points retrieved and read snapshot or archived values for one or many PI point(s). Figure 1 presents what the application should look like.

Page 3: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 3

 

Figure 1

Here are the specifications required for your application.

Part A - PI Connectivity

• When the application opens, the default PI Server must be assigned to the drop-down list box-PI Server field;

• Establish the connection when the user clicks on the Connect button; • Make sure it is not possible to connect or disconnect more than once; • Add a Picker button (… button) that will call the Connection Manager; • Close the connection with the connected PI Server when the user quits the

application without disconnecting first.

Part B - Tag Search

• When the Search button is clicked, build the WHERE clause with the specified tag mask and search for corresponding points on the server;

• Loop through all the PIPoint objects of the list, and populate a list box on the form; • Add a Picker button (… button) that will call the Tag Search dialog box.

Part C - Tag Attributes

• Get the list of all the attributes of a selected PI point;

Page 4: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 4

 

• Update the value of a point attribute; • Add a button that will display the standard Point Attributes window; • Add a functionality to let the user create a new PI point; • Add a check box field that will create a random tag using these attributes:

pointsource=R, location2=50, location4=1 and location5=1. By random tag it means a tag configured in such a way the PI Random Simulator will generate simulation values for it.

Part D - Read Tag Values

• Add a list box field to select all points from which you need to read; • Add a button to start the reading of snapshot value(s); • Add different fields to select the time range to read archived and interpolated values; • Add a field to specify the time interval for interpolated values to generate; • Add a button to start the reading of archived values; • Add a button to start the reading of interpolated values; • Add a list box that will display all values for all points with their respective

timestamps.

1.1.3 Approach

Using the Visual Studio template project complete the application’s foundation with the methods and properties required to perform the required task. To facilitate your work all the accessory development (UI, naming convention, initialization, etc.) has been done for you. Locate placeholders in the code to know where to put your code; they look like this: '<Complete the code here>.

To do this exercise, you will need to refer to the OSIsoft.PISDK, OSIsoft.PISDKCommon and OSIsoft.PITimeServer namespaces.

Page 5: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 5

 

 

Reference PI SDK Libraries

Different assemblies are required to include with your project to develop with the PI Server; you do not necessarily need all of them at all time but it is a good practice to have them ready to use. These assemblies are all installed in the GAC, so you can reference them in your project by simply browsing the list and pick the ones described in the following list:

• OSIsoft.PISDK.dll is the main PI SDK dynamic link library (DLL) – primary library for PI SDK content;

• OSIsoft.PISDKCommon.dll is used for some shared data structures; • OSIsoft.PITimeServer.dll provides parsing capabilities of time strings

and correct rendering of time in several useful forms and time arithmetic; • OSIsoft.PISDKDlg.dll contains standard PI SDK functions like tag

search and connection handling; • OSIsoft.PISDKCtl.dll contains standard PI SDK controls.

Page 6: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 6

 

Approach Part A – PI Connectivity

• When the frmPIEdit form is opened, assign the _frmPIEdit object to the current instance of the form.

• Using the PISDK object, assign the default PI server to the _srvPIServer object. • When the uxConnectButton button is clicked, check for a current connection and

close it. • Open a connection to the assigned PI Server using the user specified username and

password. • You may wish to return a message to the user to inform if the connection was

successful or not. • When the uxConnectionMgrButton button is clicked, use the

PISDKDlg.Connections object to open a Connection Manager Dialog window. • When the uxQuitButton button is clicked, close the connection to the current PI

server. • Release class level objects by assigning them the Nothing keyword.

Approach Part B - Tag Search

• Using the frmGetPIPoints form, when the uxGetPointsTagMaskButton button is clicked, form a WHERE clause using the user specified tag mask.

• Use the WHERE clause to retrieve corresponding PI Points from _srvPIServer object.

• For each PI Point in the list of retrieved PI Points, add an entry in the combo box uxAvailablePIPointsList on the _frmPIEdit form.

• On the frmPIEdit form, when the uxTagSearchButton button is clicked, use the _dlgTagSearch object to display the Tag Search dialog window.

• Have the Tag Search dialog set to initialize the search with the current server and set so that the user cannot select other servers.

• Add the PI Points retrieved to the uxAvailablePIPointsList combo box.

Approach Part C - Tag Attributes

• Assign the _CurrentPIPoint object to the PI Point selected in the uxAvailablePIPointsList combo box when the selected index is changed.

• When the uxGetAttributesButton button is clicked, retrieve the list of attributes for the selected PI Point.

• For each attribute retrieved add an entry in the uxPointAttributesList list box. • When an attribute in the list box is selected, display its value in the

uxAttributeValue text box. • When the uxChangeAttrValueButton button is clicked, update the value of the

selected attribute to a user specified value. • When the uxAttributesWindowButton button is clicked, use a

PISDKDlg.PIPointPropertySheet object to display the Point Attribute window for the selected PI Point.

• When the uxAddPointButton button is clicked create a new PI Point in the frmNewPT form.

Page 7: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 7

 

• The new PI Point will have the user specified name and point type. • If the check box for a random tag is not checked, create the PI Point with the Classic

point class. • If the check box for a random tag is checked, create the PI Point with the Classic

point class with the following attributes: pointsource = R, location2 = 50, location4 = 1 and location5 = 1.

• Update the list of PI Points on the main frmPIEdit form

Approach Part D - Read Tag Values

• When the Refresh Snapshot button is clicked, retrieve the timestamp and value of the current snapshot of the selected PI Point.

• When the Get Archive Values button is clicked, retrieve the archived data of the selected PI Point between the user specified start time and end time.

• For each data value retrieved, add an entry in the uxArcOrInterpValuesList list box with both the timestamp and value.

• You will need to make usage of the DirectCast method to convert the value attributes returned as an object into a digital state if necessary.

 

 

Try to do this exercise on your own before proceeding to the step‐by‐step solution. 

Coding Using PI SDK

• Use Imports instructions to shorten the declaration you make. • Use Try…Catch syntax to trap any errors and address them. • Assign to nothing or invoke the Dispose method when objects are no longer

needed to avoid high resource usage.

Page 8: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 8

 

1.1.4 Step-by-Step Solution

Part A - PI Connectivity

1. Start Visual Studio 2008. 2. Open the template project file located at C:\Labs\vCampus\Data Access\General PI SDK

Programming Introduction\Template\ template_PISDK_Exercises.sln by clicking on File > Open > Project / Solution.

Figure 2

3. Open the frmPIEdit_Load() method, and assign the current instance of the main form to the global form object.

_frmPIEdit = Me 4. Assign the default PI server to the _srvPIServer class-level object. _srvPIServer = _PISDK.Servers.DefaultServer

The _srvPIServer is a class-level member or object; it means it is visible to any internal or external member of the class. This method allows sharing the connection to the PI Server.

5. Use the uxConnectButton_Click event method to implement this functionality. Disconnect the currently connected PI server.

If _srvPIServer.Connected Then _srvPIServer.Close() 6. Use the uxConnectButton_Click event method to implement the connection functionality to the

server. If _srvPIServer.Connected = False Then _srvPIServer.Open() End If 7. In the uxConnectionMgrButton_Click method define a new dialog connection. Dim dlgConnManager As New PISDKDlg.Connections

Page 9: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 9

 

Figure 3

8. Display the Connection Manager as a modal window for the uxConnectionMgrButton_Click event method.

dlgConnmanager.ShowConnectionDialog(False,1)

The PI Connection Manager lists all PI servers in the Known Servers table, and their status. By clicking on the server names and activating the mouse right-click menu, the user can: connect and disconnect servers, display detailed connection information, add and delete PI Servers in the Known Servers List or change the default connection parameters.

9. The uxQuit_Button_Click event method is used to close the connection and quit the current application.

If _srvPIServer.Connected Then _srvPIServer.Close() End If 10. Release the objects. _srvPIServer = Nothing _CurrentPIPoint = Nothing

Part B - Tag Search

uxConnectionMgrButton

uxQuitButtonuxConnectButton

Page 10: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 10

 

This section of the lab will be done in the PI Point Handling and the Class Internal Methods regions.

Regions

Visual Studio .NET introduced to possibility to outline portions of text in the code editor; this is a very useful feature that helps navigating through huge sections of code. In Visual Basic .NET these outlines are enclosed between the #Region ... #End Region keywords.

Figure 4

1. From the frmGetPIPoints.vb form, build a string with the entered tag mask in the uxSearchButton_Click event method.

strWhereClause = "Tag = """ & uxTagMask.Text & """" 2. Define a PointList object. Dim List As PointList 3. Use the GetPoints method to retrieve PI Points with the WHERE string List = _frmPIEdit._srvPIServer.GetPoints(strWhereClause) 4. Remove the condition ListCount = 0 and replace it with the PointList.Count property. The

uxSearchButtonuxAvailablePIPointsList

Page 11: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 11

 

ListCount object is a dummy one to allow the compilation of the application. 5. Loop through all of the retrieved PI Points and add an entry to the combo box

uxAvailablePIPointsList on the main frmPIEdit form. For Each Point as PIPoint in List _frmPIEdit.uxAvailablePIPointsList.Items.Add(Point.Name) Next

Through steps 6 to 8, there is an alternate way to perform the same task as we just did but by employing the Tag Search dialog.

6. Now from the uxTagSearchButton_Click event method, add the current PI Server to a collection.

PIServersCollection.Add(_srvPIServer.Name, "") 7. Display the Tag Search window using the _dlgTagSearch object and return the selected points

· Use the tsoptDisableServerPickList option to prevent the user from searching another PI Server

Points = _dlgTagSearch.Show(PIServersCollection, _ PISDKDlg.TagSearchOptions.tsoptDisableServerPickList) 8. Loop through all of the retrieved PI Points and add an entry for each to the combo box. For Each Point As PISDK.PIPoint In Points 'Add the name of the PI Point to the combo box. uxAvailablePIPointsList.Items.Add(Point.Name) Next

Part C - Tag Attributes

This section of the lab will be done in the PI Point Handling and the Class Internal Methods regions.

Page 12: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 12

 

Figure 5

1. Use the point name selected in the combo box to retrieve the desired PI Point from the current server. Modify the uxAvailablePIPointsList_SelectedIndexChanged event method by assigning this point to the _CurrentPIPoint object.

_CurrentPIPoint = _srvPIServer.PIPoints(uxAvailablePIPointsList.Text) 2. Add an entry in the point attribute list box for each point property in the attribute list for the selected

PI Point for the uxGetAttributesButton_Click event method. For Each Attribute As PISDK.PointAttribute In _CurrentPIPoint.PointAttributes uxPointAttributesList.Items.Add(Attribute.Name) Next 3. Get the value of the selected attribute with the

uxPointAttributesList_SelectedIndexChanged event method and update the value of the text box.

uxAttributeValue.Text = _ _CurrentPIPoint.PointAttributes.Item(uxPointAttributesList.Text).Value 4. From the uxChangeAttrValueButton_Click event method, allow property modification by

disabling the ReadOnly property on the PI Point Attributes. _CurrentPIPoint.PointAttributes.ReadOnly = False

uxAvailablePIPointsList

uxGetAttributesButton

uxChangeAttrValueButton

uxAddButton

uxAttributesWindowButton

Page 13: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 13

 

The ReadOnly property of the PointAttributes collection is a Boolean data type indicating whether or not the program can change the values of attributes within the collection.

5. Modify the selected property by assigning it the specified value. _CurrentPIPoint.PointAttributes.Item(uxPointAttributesList.Text).Value = _ uxAttributeValue.Text 6. Remove the property modifications rights. _CurrentPIPoint.PointAttributes.ReadOnly = True 7. From the uxAttributesWindowButton_Click event method, add the current PI Point to a

PointList collection. Dim ptlSelectedPoint As New PISDK.PointList ptlSelectedPoint.Add(_CurrentPIPoint) 8. Display the Point Attribute dialog window as a modal window from the

uxAttributesWindowButton_Click event method. dlgAttributes.Show(ptlSelectedPoint, 1) 9. Open the frmNewPT.vb form.

Figure 6

10. Open the Class Internal Methods region and modify the uxAddButton_Click event method. Retrieve the specified point name.

strPoint = uxPointName.Text 11. Detect the user specified point type. If uxPointTypeOption1.Checked = True Then lngPointType = PointTypeConstants.pttypFloat16 If uxPointTypeOption2.Checked = True Then lngPointType = PointTypeConstants.pttypFloat32

Page 14: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 14

 

If uxPointTypeOption3.Checked = True Then lngPointType = PointTypeConstants.pttypFloat64 If uxPointTypeOption4.Checked = True Then lngPointType = PointTypeConstants.pttypInt16 If uxPointTypeOption5.Checked = True Then lngPointType = PointTypeConstants.pttypInt32 If uxPointTypeOption6.Checked = True Then lngPointType = PointTypeConstants.pttypString 12. If the random tag box is not checked, create the point using the specified name and type with the

Classic point type. If chkRandomTag.Checked = False Then ptReturned = _frmPIEdit._srvPIServer.PIPoints.Add(strPoint, "Classic", _ lngPointType) ... 13. If the random tag box is checked, populate a collection with the specified attributes. Else nvAttributes.Add("pointsource", "R") nvAttributes.Add("location2", 50) nvAttributes.Add("location4", 1) nvAttributes.Add("location5", 1)

The nvAttributes parameter is a NamedValues collection object containing NamedValue objects whose name property represents an attribute and whose value property is a variant representing the desired value for the attribute.

14. Create the point using the previously specified name, type, point class Classic, and the created attributes.

ptReturned = _frmPIEdit._srvPIServer.PIPoints.Add(strPoint, "Classic", _ lngPointType, nvAttributes) End If 15. Update the PI Points combo box on the main frmPIEdit form. _frmPIEdit.uxAvailablePIPointsList.Items.Add(strPoint) _frmPIEdit.uxAvailablePIPointsList.Text = strPoint 16. Save and close the frmNewPT form.

Part D - Read Tag Values

This section of the lab will be done in the PI Point Handling and the Class Internal Methods regions.

1. Retrieve the currently selected PI Point from the uxRefreshSnapshotValueButton_Click event method.

_CurrentPIPoint = _srvPIServer.PIPoints(uxAvailablePIPointsList.Text) 2. Return the snapshot timestamp to the user, and format it to PI Time Format. uxSnapshotValueDate.Text = _ Format(_CurrentPIPoint.Data.Snapshot.TimeStamp.LocalDate, "dd-MMM-yyyy HH:mm:ss")

Page 15: General PI SDK Programming Introduction and Best Practices PISDK Programming/2 General PISDK... · 2012-01-25 · 2. C:\Labs\vCampus\Data Access\General PI SDK Open the template project

 

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, photocopying, recording, or otherwise, without the prior written permission of OSIsoft, LLC. © Copyright 1995-2009 OSIsoft, LLC, 777 Davis St., Suite 250, San Leandro, CA 94577

Page 15

 

The PITime the simplest object (which is the object returned by the TimeStamp property) used to represent a specific time in the PI SDK. Internally it stores time in UTC. The object is server independent, meaning it has no notion of the time zone where it originated. It provides read and write access to the stored time in a few basic formats by the different class properties such as LocalDate and UTCSeconds. When reading or writing to a property that exposes the time in local (wall clock) format, all conversions are made based on the time zone settings for the system where the object is executing.

3. Return the snapshot value to the user. uxSnapshotValueValue.Text = _CurrentPIPoint.Data.Snapshot.Value.ToString 4. Retrieve the currently selected PI Point from the uxGetArchivedValuesButton_Click event

method. _CurrentPIPoint = _srvPIServer.PIPoints(uxAvailablePIPointsList.Text) 5. Define a new PIValues object to store the archive values. Dim pvsArchivedValues As New PIValues 6. Retrieve the archived values for the selected PI Point, using the user specified start and end times. pvsArchivedValues = _CurrentPIPoint.Data.RecordedValues( _ uxArcOrInterpStartTime.Text, _ uxArcOrInterpEndTime.Text, _ BoundaryTypeConstants.btInside) 7. For each retrieved value, add an entry to the lstArcOrInterpValues listbox. Be sure to check if

the value returned is a digital state. For Each pvTempValue As PIValue In pvsArchivedValues 'Checks if the value is a digital state. If TypeOf (pvTempValue.Value) Is DigitalState Then uxArcOrInterpValuesList.Items.Add( _ Format(pvTempValue.TimeStamp.LocalDate, "dd-MMM-yy HH:mm:ss") _ & " " & DirectCast(pvTempValue.Value, DigitalState).Name) Else uxArcOrInterpValuesList.Items.Add( _ Format(pvTempValue.TimeStamp.LocalDate, "dd-MMM-yy HH:mm:ss") _ & " " & pvTempValue.Value) End If Next

The usage of DirectCast method is to allow the conversion of the value into a digital state if necessary.