From 9c6d8830a1c555523137313a2a215352e2baaf87 Mon Sep 17 00:00:00 2001 From: Stone Date: Wed, 13 Dec 2023 13:05:16 -0600 Subject: [PATCH] Added recorded_values_by_count function utilizing full PI API - allows user to pull specified number of values, either forward or backward, using a filtering expression. I use this frequently in excel to find the time when a totalizer point equaled a value of interest. --- PIconnect/PIData.py | 68 +++++++++++++++++++++++++++++++++++++++++ PIconnect/PIPoint.py | 12 ++++++++ PIconnect/_typing/PI.py | 11 +++++++ 3 files changed, 91 insertions(+) diff --git a/PIconnect/PIData.py b/PIconnect/PIData.py index bf94965ae..db4462c33 100644 --- a/PIconnect/PIData.py +++ b/PIconnect/PIData.py @@ -595,3 +595,71 @@ def _update_value( buffer_mode: AF.Data.AFBufferOption, ) -> None: pass + +#added recorded_values_by_count + def recorded_values_by_count( + self, + startTime: _time.TimeLike, + count: int = 1, + forward: bool = True, + boundaryType: AF.Data.AFBoundaryType = AF.Data.AFBoundaryType.Inside, + filterExpression: str = '', + includeFilteredValues: bool = False + ) -> PISeries: + """recorded_value_by_count + + Return a PISeries with the specified number of compressed values beginning at the requested time + Args: + start_time (str): String containing the date, and possibly time, + to start the request. This is parsed, using + :afsdk:`AF.Time.AFTime `. + count (int): The number of compressed values to return. This value must be greater than zero. + forward (bool): + A value of true indicates to begin at the start time and move forward in time. + A value of false indicates to move backward in time. + When moving backward, values will be returned in time descending order. + boundary_type (str, optional): Defaults to 'inside'. Key from the + `__boundary_types` dictionary to describe how to handle the + boundaries of the time range. + filter_expression (str): + Query on which to filter data to include in the results. See :ref:`filtering_values` + for more information on filter queries. + include_filtered (bool): + Specify to indicate that values which fail the filter criteria are present in the returned + data at the times where they occurred with a value set to a "Filtered" enumeration value with bad status. + Repeated consecutive failures are omitted. + + Returns: + PISeries: A PISeries with a single row, with the corresponding time as + the index + """ + from . import _time as time_module + + _startTime = time_module.to_af_time(startTime) + _filterExpression = self._normalize_filter_expression(filterExpression) + + pivalues = self._recorded_values_by_count(_startTime, count,forward, boundaryType, _filterExpression, includeFilteredValues) + + timestamps: List[datetime.datetime] = [] + values: List[Any] = [] + for value in pivalues: + timestamps.append(_time.timestamp_to_index(value.Timestamp.UtcTime)) + values.append(value.Value) + return PISeries( # type: ignore + tag=self.name, + timestamp=timestamps, + value=values, + uom=self.units_of_measurement, + ) + + @abc.abstractmethod + def _recorded_values_by_count( + self, + startTime: AF.Time.AFTime, + count: int, + forward: bool, + boundaryType: AF.Data.AFBoundaryType, + filterExpression: str, + includeFilteredValues: bool + ) -> AF.Asset.AFValues: + pass \ No newline at end of file diff --git a/PIconnect/PIPoint.py b/PIconnect/PIPoint.py index 601f4833e..7cc020f0b 100644 --- a/PIconnect/PIPoint.py +++ b/PIconnect/PIPoint.py @@ -176,3 +176,15 @@ def _update_value( buffer_mode: AF.Data.AFBufferOption, ) -> None: return self.pi_point.UpdateValue(value, update_mode, buffer_mode) + + # Added _update_recorded_values_by_count + def _recorded_values_by_count( + self, + startTime: AF.Time.AFTime, + count: int, + forward: bool, + boundaryType: AF.Data.AFBoundaryType, + filterExpression: str, + includeFilteredValues: bool + ) -> AF.Asset.AFValues: + return self.pi_point.RecordedValuesByCount(startTime, count, forward, boundaryType, filterExpression, includeFilteredValues) diff --git a/PIconnect/_typing/PI.py b/PIconnect/_typing/PI.py index 53f3781ae..0543347ec 100644 --- a/PIconnect/_typing/PI.py +++ b/PIconnect/_typing/PI.py @@ -153,3 +153,14 @@ def UpdateValue( /, ) -> None: pass + + @staticmethod + def RecordedValuesByCount( + start_time: Time.AFTime, + count: int, + forward: bool, + boundaryType: Data.AFBoundaryType, + filterExpression: str, + includeFilteredValues: bool + ) -> _values.AFValues: + return _values.AFValues() \ No newline at end of file