Skip to content

Commit 80033de

Browse files
author
osimloeff
committed
Added get_summary_values on DataApi class
1 parent 1b1e3f3 commit 80033de

File tree

6 files changed

+186
-2
lines changed

6 files changed

+186
-2
lines changed

CONTRIBUTING.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
Contributing to any PI Web API client library for Python
3+
============================
4+
5+
6+
How to contribute
7+
-----------------
8+
9+
The preferred workflow for contributing to scikit-learn is to fork the
10+
main repository on GitHub, clone, and develop on a branch. Steps:
11+
12+
1. Fork the project repository by clicking on the 'Fork' button near the top right of the page. This creates
13+
a copy of the code under your GitHub user account. For more details on
14+
how to fork a repository see [this guide](https://help.github.com/articles/fork-a-repo/).
15+
16+
2. Clone your fork of the osimloeff repo from your GitHub account to your local disk:
17+
18+
```bash
19+
$ git clone [email protected]:YourLogin/PI-Web-API-Client-Python.git
20+
$ cd PI-Web-API-Client-Python
21+
```
22+
23+
3. Create a ``feature`` branch to hold your development changes:
24+
25+
```bash
26+
$ git checkout -b my-feature
27+
```
28+
29+
Always use a ``feature`` branch. It's good practice to never work on the ``master`` branch!
30+
31+
4. Develop the feature on your feature branch. Add changed files using ``git add`` and then ``git commit`` files:
32+
33+
```bash
34+
$ git add modified_files
35+
$ git commit
36+
```
37+
38+
to record your changes in Git, then push the changes to your GitHub account with:
39+
40+
```bash
41+
$ git push -u origin my-feature
42+
```
43+
44+
5. Follow [these instructions](https://help.github.com/articles/creating-a-pull-request-from-a-fork) or [this video](https://www.youtube.com/watch?v=YTbRzhQju4c)
45+
to create a pull request from your fork. This will send an email to the committers.
46+
47+
(If any of the above seems like magic to you, please look up the
48+
[Git documentation](https://git-scm.com/documentation) on the web, or ask a friend or another contributor for help.)
49+

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ All classes and methods are described on the [DOCUMENTATION](DOCUMENTATION.md).
5050

5151
- 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.
5252
- The X-Requested-With header is added to work with CSRF defences.
53+
54+
55+
## Contributing
56+
57+
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.
5358

5459
## Examples
5560

docs/api/DataApi.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Method | HTTP request | Description
55
[**get_recorded_values**](DataApi.md#get_recorded_values) | Returns a pandas dataframe with compressed values for the requested time range from the source provider.
66
[**get_interpolated_values**](DataApi.md#get_interpolated_values) | Retrieves a pandas dataframe with interpolated values over the specified time range at the specified sampling interval.
77
[**get_plot_values**](DataApi.md#get_plot_values*) | Retrieves a pandas dataframe with values over the specified time range suitable for plotting over the number of intervals (typically represents pixels).
8+
[**get_summary_values**](DataApi.md#get_summary_values*) | Returns a data frame with the summary over the specified time range for the stream.
89
[**get_multiple_recorded_values**](DataApi.md#get_multiple_recorded_values) | Returns an array of pandas dataframe with recorded values of the specified streams.
910
[**get_multiple_interpolated_values**](DataApi.md#get_multiple_interpolated_values) | Returns a dataframe with interpolated values of the specified streams over the specified time range at the specified sampling interval.
1011
[**get_multiple_plot_values**](DataApi.md#get_multiple_plot_values) | Returns a pandas dataframe with values of the specified streams over the specified time range suitable for plotting over the number of intervals (typically represents pixels).
@@ -93,6 +94,35 @@ Pandas Dataframe
9394
[[Back to top]](#) [[Back to API list]](../../DOCUMENTATION.md#documentation-for-api-endpoints) [[Back to Model list]](../../DOCUMENTATION.md#documentation-for-models) [[Back to DOCUMENTATION]](../../DOCUMENTATION.md)
9495

9596

97+
# **get_summary_values**
98+
> get_summary('path', 'calculation_basis', 'end_time', 'filter_expression', 'sample_interval', 'sample_type', 'selected_fields', 'start_time', 'summary_duration', 'summary_type', 'time_type', 'time_zone')
99+
100+
Returns a data frame with the summary over the specified time range for the stream.
101+
102+
### Parameters
103+
104+
Name | Type | Description | Notes
105+
------------- | ------------- | ------------- | -------------
106+
**path** | **list[str]**| The paths of multiple streams (for a PI Point use "pi:\\servername\pointname" or "af:\\afservername\database\element|attribute" for an attribute). | [required]
107+
**calculation_basis** | **str**| Specifies the method of evaluating the data over the time range. The default is 'TimeWeighted'.. | [optional]
108+
**end_time** | **str**| An optional end time. The default is '*' for element attributes and points. For event frame attributes, the default is the event frame's end time, or '*' if that is not set. Note that if endTime is earlier than startTime, the resulting values will be in time-descending order.. | [optional]
109+
**filter_expression** | **str**| A string containing a filter expression. Expression variables are relative to the attribute. Use '.' to reference the containing attribute.. | [optional]
110+
**sample_interval** | **str**| When the sampleType is Interval, sampleInterval specifies how often the filter expression is evaluated when computing the summary for an interval.. | [optional]
111+
**sample_type** | **str**| Defines the evaluation of an expression over a time range. The default is 'ExpressionRecordedValues'.. | [optional]
112+
**selected_fields** | **str**| List of fields to be returned in the response, separated by semicolons (;). If this parameter is not specified, all available fields will be returned.. | [optional]
113+
**start_time** | **str**| An optional start time. The default is '*-1d' for element attributes and points. For event frame attributes, the default is the event frame's start time, or '*-1d' if that is not set.. | [optional]
114+
**summary_duration** | **str**| The duration of each summary interval. If specified in hours, minutes, seconds, or milliseconds, the summary durations will be evenly spaced UTC time intervals. Longer interval types are interpreted using wall clock rules and are time zone dependent.. | [optional]
115+
**summary_type** | **list[str]**| Specifies the kinds of summaries to produce over the range. The default is 'Total'. Multiple summary types may be specified by using multiple instances of summaryType.. | [optional]
116+
**time_type** | **str**| Specifies how to calculate the timestamp for each interval. The default is 'Auto'.. | [optional]
117+
**time_zone** | **str**| The time zone in which the time string will be interpreted. This parameter will be ignored if a time zone is specified in the time string. If no time zone is specified in either places, the PI Web API server time zone will be used.. | [optional]
118+
119+
120+
### Return type
121+
122+
[**PIItemsSummaryValue**](../models/PIItemsSummaryValue.md)
123+
124+
[[Back to top]](#) [[Back to API list]](../../DOCUMENTATION.md#documentation-for-api-endpoints) [[Back to Model list]](../../DOCUMENTATION.md#documentation-for-models) [[Back to DOCUMENTATION]](../../DOCUMENTATION.md)
125+
96126

97127
# **get_multiple_recorded_values**
98128
> get_multiple_recorded_values('path', 'boundary_type', 'end_time', 'filter_expression', 'include_filtered_values', 'max_count', 'selected_fields', 'start_time', 'time_zone')

osisoft/pidevclub/piwebapi/api/data_api.py

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,87 @@ def convert_multiple_streams_to_df(self, items, gatherInOneDataFrame, web_ids, s
9292
dfs[key] = df
9393
return dfs
9494

95+
def convert_summary_to_df(self, items, selected_fields):
9596

97+
if (items is None):
98+
raise Exception('The returned data is Null or None')
99+
100+
streamsLength = len(items)
101+
if (streamsLength == 0):
102+
raise Exception('The returned data is Null or None')
103+
104+
105+
addValues = False
106+
addTimeStamp = False
107+
addUnitAbbr = False
108+
addGood = False
109+
addQuestionable = False
110+
addSubstituted = False
111+
value = []
112+
timestamp = []
113+
unitsAbbreviation = []
114+
good = []
115+
questionable = []
116+
substituted = []
117+
summaryType = []
118+
119+
if (selected_fields != None and selected_fields != ""):
120+
if ("timestamp" in selected_fields):
121+
addTimeStamp = True
122+
if ("value" in selected_fields):
123+
addValues = True
124+
125+
if ("questionable" in selected_fields):
126+
addQuestionable = True
127+
128+
if ("unitabbr" in selected_fields):
129+
addUnitAbbr = True
130+
131+
if ("good" in selected_fields):
132+
addGood = True
133+
134+
if ("substituted" in selected_fields):
135+
addSubstituted = True
136+
else:
137+
addValues = True
138+
addTimeStamp = True
139+
addUnitAbbr = True
140+
addGood = True
141+
addQuestionable = True
142+
addSubstituted = True
143+
144+
145+
for item in items:
146+
summaryType.append(item.type)
147+
if (addValues == True):
148+
value.append(item.value.value)
149+
if (addTimeStamp == True):
150+
timestamp.append(item.value.timestamp)
151+
if (addUnitAbbr == True):
152+
unitsAbbreviation.append(item.value.units_abbreviation)
153+
if (addGood == True):
154+
good.append(item.value.good)
155+
if (addQuestionable == True):
156+
questionable.append(item.value.questionable)
157+
if addSubstituted == True:
158+
substituted.append(item.value.substituted)
159+
160+
data = {}
161+
data['SummaryType'] = summaryType
162+
if (addValues == True):
163+
data['Value'] = value;
164+
if (addTimeStamp == True):
165+
data['Timestamp'] = timestamp;
166+
if (addUnitAbbr == True):
167+
data['UnitsAbbreviation'] = unitsAbbreviation;
168+
if (addGood == True):
169+
data['Good'] = good;
170+
if (addQuestionable == True):
171+
data['Questionable'] = questionable;
172+
if (addSubstituted == True):
173+
data['Substituted'] = substituted;
174+
df = pd.DataFrame(data)
175+
return df
96176

97177
def convert_to_df(self, items, selected_fields):
98178

@@ -171,7 +251,7 @@ def convert_to_df(self, items, selected_fields):
171251
if (addSubstituded == True):
172252
data['Substituted'] = substituted;
173253
df = pd.DataFrame(data)
174-
return df
254+
return df
175255

176256
def get_recorded_values(self, path, boundary_type=None, desired_units=None, end_time="*", filter_expression=None, include_filtered_values=None, max_count=None, selected_fields=None, start_time="*-1h", time_zone=None):
177257
if (path is None):
@@ -206,6 +286,18 @@ def get_plot_values(self, path, desired_units=None, end_time="*", intervals = 10
206286
df = self.convert_to_df(res.items, selected_fields)
207287
return df
208288

289+
def get_summary_values(self, path, calculation_basis='TimeWeighted', end_time="*", filter_expression=None, sample_interval=None, sample_type='ExpressionRecordedValues', selected_fields=None, start_time="*-1d", summary_duration=None, summary_type=['Total'], time_type='Auto', time_zone=None):
290+
if (path is None):
291+
print("The variable path cannot be null.")
292+
return
293+
294+
web_id = self.convert_path_to_web_id(path)
295+
res = self.streamApi.get_summary(web_id, calculation_basis, end_time, filter_expression,
296+
sample_interval, sample_type, selected_fields, start_time, summary_duration,
297+
summary_type, time_type, time_zone)
298+
df = self.convert_summary_to_df(res.items, selected_fields)
299+
return df
300+
209301
def get_multiple_interpolated_values(self, paths, end_time="*", filter_expression=None, include_filtered_values=None, interval="1h", selected_fields=None, sort_field=None, sort_order=None, start_time="*-1d", sync_time=None, sync_time_boundary_type=None, time_zone=None, web_id_type=None):
210302
if (paths is None):
211303
print("The variable paths cannot be null.")

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from setuptools import setup, find_packages
1919

2020
NAME = "osisoft.pidevclub.piwebapi"
21-
VERSION = "1.11.0"
21+
VERSION = "1.11.1"
2222
# To install the library, run the following
2323
#
2424
# python setup.py install

test/test_data.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ def test_data_recorded(self):
7272
df12 = client.data.get_plot_values("af:\\\\PISRV1\\Universities\\UC Davis\\Buildings\\Academic Surge Building\\Electricity|AnnualUsage", None, "*", 20, None, "*-40d", None)
7373
pass
7474

75+
def test_data_summary(self):
76+
client = self.getPIWebApiClient()
77+
df1 = client.data.get_summary_values("pi:\\\\PISRV1\\sinusoid", start_time="*-1d", end_time="*",
78+
summary_type=['Average'], summary_duration='1h')
79+
df2 = client.data.get_summary_values("pi:\\\\PISRV1\\sinusoid", start_time="*-1d", end_time="*",
80+
summary_type=['Average', 'Total'], summary_duration='1h')
81+
pass
82+
7583
def test_getExceptionError(self):
7684
client = self.getPIWebApiClient()
7785
paths=["pi:\\\\PISRV1\\sinusoid", "pi:\\\\PISRV1\\sinusoidu", "pi:\\\\PISRV1\\cdt158"]

0 commit comments

Comments
 (0)