PI Web API client library for Python (2018)
===

## Overview
This repository has the source code package of the PI Web API client libraries for Python. This version was developed on top of the PI Web API 2018 swagger specification.

## Requirements

 - PI Web API 2018 installed within your domain using Kerberos(NTLM fallback) or Basic Authentication. If you are using an older version, some methods might not work.
 - Python 2.7 and 3.4+

## Installation
### pip install

```sh
pip install osipiconnect
```

The python package is hosted on Github, you can install directly from Github


```sh
pip install git+https://github.com/vivekgoyanka/osipiconnect
```

You may need to run `pip` with root permission(for linux). If you are using Windows, remember to open the command prompt running as administrator. You must have Git installed on your machine.

Then import the package:
```python
import osisoft.pidevclub.piwebapi 
```

This library was tested using PyCharm 2018.1.2.

## Documentation

All classes and methods are described on the [DOCUMENTATION](DOCUMENTATION.md). 

## Notes

 - Is is highly recommended to turn debug mode on in case you are using PI Web API 2017 R2+ in order to receive more detailed exception errors. This can be achieved by creating or editing the DebugMode attribute's value to TRUE from the System Configuration element.
 - The X-Requested-With header is added to work with CSRF defences.


## Contributing

We welcome new contributors of all experience levels. Please follow our [this page](https://github.com/osimloeff/PI-Web-API-Client-Python/blob/master/CONTRIBUTING.md) to learn how to do it.
 
## Examples

Please check the [test_main.py](/test/test_main.py) from this repository. Below there are also code snippets written in Python for you to get started using this library:


### Create an instance of the PI Web API top level object.

#### Basic Authentication
```python
    from osisoft.pidevclub.piwebapi.pi_web_api_client import PIWebApiClient
    client = PIWebApiClient("https://test.osisoft.com/piwebapi", useNTLM=False, username="username", password="password", verifySsl=true)  
``` 

#### NTLM Authentication(Kerberos will not work for this library)
```python
    from osisoft.pidevclub.piwebapi.pi_web_api_client import PIWebApiClient
    client = PIWebApiClient("https://test.osisoft.com/piwebapi", useNTLM=True, username="username", password="password")  
``` 




### Retrieving PI data to an Python pandas data frame


```python
    df1 = client.data.get_recorded_values("pi:\\\\PISRV1\\sinusoid", start_time="*-1d", end_time="*")
    df2 = client.data.get_interpolated_values("pi:\\PISRV1\\sinusoid", start_time="*-1d", end_time="*", interval="1h")
    df3 = client.data.get_plot_values("pi:\\\\PISRV1\\sinusoid", end_time="*", intervals=15, start_time= "*-1d")
    df4 = client.data.get_recorded_values("pi:\\\\PISRV1\\sinusoid", start_time="*-1d", end_time="*", selected_fields="items.value;items.timestamp")
	
    paths  = ["pi:\\\\PISRV1\\sinusoid", "pi:\\\\PISRV1\\sinusoidu", "pi:\\\\PISRV1\\cdt158"];
    dfs1 = client.data.get_multiple_recorded_values(paths, start_time="*-1d", end_time= "*")
    dfs2 = client.data.get_multiple_interpolated_values(paths, start_time="*-1d", end_time="*", interval="1h")
    dfs3 = client.data.get_multiple_plot_values(paths,  start_time="*-1d", end_time="*", intervals="14")
    dfs4 = client.data.get_multiple_recorded_values(paths, start_time="*-1d", end_time="*", selected_fields="items.items.value;items.items.timestamp")
```

The path from the methods above should start with "pi:" (if your stream is a PI Point) or "af:" (if your stream is an AF attribute).




### Get the PI Data Archive WebId

```python
    dataServer = client.dataServer.get_by_path("\\\\PISRV1");
```

### Create a new PI Point

```python
    newPoint = PIPoint()
    newPoint.name  = "SINUSOID_TEST"
    newPoint.descriptor = "Test PI Point for Python PI Web API Client"
    newPoint.point_class = "classic"
    newPoint.point_type = "float32"
    newPoint.future = False
    res = client.dataServer.create_point_with_http_info(dataServer.web_id, newPoint);         
```

### Get PI Points WebIds

```python
    point1 = client.point.get_by_path("\\\\PISRV1\\sinusoid");
    point2 = client.point.get_by_path("\\\\PISRV1\\cdt158");
    point3 = client.point.get_by_path("\\\\PISRV1\\sinusoidu");
```

### Get recorded values in bulk using the StreamSet/GetRecordedAdHoc

```python
    webIds = list()
    webIds.append(point1.web_id);
    webIds.append(point2.web_id);
    webIds.append(point3.web_id);
    piItemsStreamValues = client.streamSet.get_recorded_ad_hoc(webIds, start_time="*-3d", end_time="*",
                                                                   include_filtered_values=True, max_count=1000)
            
```

### Send values in bulk using the StreamSet/UpdateValuesAdHoc

```python
    streamValuesItems = PIItemsStreamValues()
    streamValue1 = PIStreamValues()
    streamValue2 = PIStreamValues()
    streamValue3 = PIStreamValues()
	
    value1 = PITimedValue()
    value2 = PITimedValue()
    value3 = PITimedValue()
    value4 = PITimedValue()
    value5 = PITimedValue()
    value6 = PITimedValue()
	
    value1.value = 2
    value1.timestamp = ("*-1d")
    value2.value = 3
    value2.timestamp = ("*-2d")
    value3.value = 4
    value3.timestamp = ("*-1d")
    value4.value = 5
    value4.timestamp = ("*-2d")
    value5.value = 6
    value5.timestamp = ("*-1d")
    value6.value = 7
    value6.timestamp = ("*-2d")

    streamValue1.web_id = point1.web_id
    streamValue2.web_id = point2.web_id
    streamValue3.web_id = point3.web_id

    values1 = list()
    values1.append(value1)
    values1.append(value2)
    streamValue1.items = values1

    values2 = list()
    values2.append(value3)
    values2.append(value4)
    streamValue2.items = values2

    values3 = list()
    values3.append(value5)
    values3.append(value6)
    streamValue3.items = values3

    streamValues = list()
    streamValues.append(streamValue1)
    streamValues.append(streamValue2)
    streamValues.append(streamValue3)
    response = client.streamSet.update_values_ad_hoc_with_http_info(streamValues)
```

### PI Web API Batch

```python
    req1 = PIRequest()
    req2 = PIRequest()
    req3 = PIRequest()
    req1.method = "GET"
    req1.resource = "https://localhost/piwebapi/points?path=\\\\MARC-PI2016\\sinusoid"
    req2.method = "GET"
    req2.resource = "https://localhost/piwebapi/points?path=\\\\MARC-PI2016\\cdt158"
    req3.method = "GET"
    req3.resource = "https://localhost/piwebapi/streamsets/value?webid={0}&webid={1}"
    req3.parameters = ["$.1.Content.WebId", "$.2.Content.WebId"]
    req3.parent_ids = ["1", "2"]

    batch = {
		"1": req1,
		"2": req2,
		"3": req3
    }

    batchResponse = client.batch.execute(batch)
    point1 = client.api_client.deserialize_object(batchResponse["1"].content, 'PIPoint')
    point2 = client.api_client.deserialize_object(batchResponse["2"].content, 'PIPoint')
    itemsStreamValue = client.api_client.deserialize_object(batchResponse["3"].content, 'PIItemsStreamValue') 
```


### Get an element and an attribute by path

```python
    element = client.element.get_by_path("\\\\PISRV1\\City Bikes\\(TO)BIKE")
    attribute = client.attribute.get_by_path("\\\\PISRV1\\City Bikes\\(TO)BIKE\\01. Certosa   P.le Avis|Empty Slots",
                                                 selected_fields="Name")     
```

### Generating Web ID 2.0 and getting information


```python
    client = self.getPIWebApiClient()
    pi_data_server_web_id = client.webIdHelper.generate_web_id_by_path("\\\\PISRV1", type(PIDataServer()), None)
    point1_web_id = client.webIdHelper.generate_web_id_by_path("\\\\PISRV1\\SINUSOID", type(PIPoint()))
    point2_web_id = client.webIdHelper.generate_web_id_by_path("\\\\PISRV1\\CDT158", type(PIPoint()))
    point3_web_id = client.webIdHelper.generate_web_id_by_path("\\\\PISRV1\\SINUSOIDU", type(PIPoint()))
    pi_attribute_web_id = client.webIdHelper.generate_web_id_by_path(
		"\\\\PISRV1\\Universities\\UC Davis\\Buildings\\Academic Surge Building|Electricity Totalizer",
		type(PIAttribute()), type(PIElement()))

    pi_element_web_id= client.webIdHelper.generate_web_id_by_path(
		"\\\\PISRV1\\Universities\\UC Davis\\Buildings\\Academic Surge Building", type(PIElement()), None)


    pi_data_server = client.dataServer.get(pi_dataServer_web_id)
    pi_attribute = client.attribute.get(pi_attribute_web_id)
    pi_element = client.element.get(pi_element_web_id)

    pi_attribute_web_id_info = client.webIdHelper.get_web_id_info(pi_attribute_web_id)
    pi_element_web_id_info= client.webIdHelper.get_web_id_info(pi_element_web_id)
    pi_dataServer_web_id_info = client.webIdHelper.get_web_id_info(pi_data_server_web_id)
```
	
### StreamUpdates


```python
    events = list()
    piItemsStreamUpdatesRegister = client.streamSet.register_stream_set_updates(webIds)
    markers = [i.latest_marker for i in piItemsStreamUpdatesRegister.items]
    k = 3
    while k > 0:
		piItemsStreamUpdatesRetrieve = client.streamSet.retrieve_stream_set_updates(markers)
		markers = [i.latest_marker for i in piItemsStreamUpdatesRetrieve.items]
		for item in piItemsStreamUpdatesRetrieve.items:
			for event in item.events:
				events.append(event)
		time.sleep(30)
		k = k-1
    self.assertTrue(events.__len__() > 0)
```	



## Licensing
Copyright 2018 OSIsoft, LLC.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
   
Please see the file named [LICENSE.md](LICENSE.md).
