Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write Values to PI #540

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion PIconnect/AFSDK.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ class AF:
"""Mock class of the AF namespace
"""

class Asset:
""" Mock class of the AF.Asset namespace"""
class AFValue:
"""" Mock class of the AF.Assets.AFValue class"""

class Data:
"""Mock class of the AF.Data namespace
"""
Expand Down Expand Up @@ -184,7 +189,6 @@ class PISystems:
"""

DefaultPISystem = None
Version = "0.0.0.0"

def __init__(self):
self._init()
Expand Down
45 changes: 10 additions & 35 deletions PIconnect/PI.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@
from PIconnect._operators import OPERATORS, add_operators
from PIconnect.AFSDK import AF
from PIconnect.PIData import PISeries, PISeriesContainer
from PIconnect.PIConsts import AuthenticationMode


class PIServer(object): # pylint: disable=useless-object-inheritance
"""PIServer is a connection to an OSIsoft PI Server
"""PIServer is a connection to a OSIsoft PI Server

Args:
server (str, optional): Name of the server to connect to, defaults to None
Expand All @@ -78,45 +77,17 @@ class PIServer(object): # pylint: disable=useless-object-inheritance
#: Default server, as reported by the SDK
default_server = AF.PI.PIServers().DefaultPIServer

def __init__(
self,
server=None,
username=None,
password=None,
domain=None,
authentication_mode=AuthenticationMode.PI_USER_AUTHENTICATION,
):
def __init__(self, server=None):
if server and server not in self.servers:
message = 'Server "{server}" not found, using the default server.'
warn(message=message.format(server=server), category=UserWarning)
if bool(username) != bool(password):
raise ValueError(
"When passing credentials both the username and password must be specified."
)
if domain and not username:
raise ValueError(
"A domain can only specified together with a username and password."
)
if username:
from System.Net import NetworkCredential
from System.Security import SecureString

secure_pass = SecureString()
for c in password:
secure_pass.AppendChar(c)
cred = [username, secure_pass] + ([domain] if domain else [])
self._credentials = (NetworkCredential(*cred), int(authentication_mode))
else:
self._credentials = None
self.connection = self.servers.get(server, self.default_server)

def __enter__(self):
if self._credentials:
self.connection.Connect(*self._credentials)
else:
# Don't force to retry connecting if previous attempt failed
force_connection = False
self.connection.Connect(force_connection)
force_connection = (
False
) # Don't force to retry connecting if previous attempt failed
self.connection.Connect(force_connection)
return self

def __exit__(self, *args):
Expand Down Expand Up @@ -255,6 +226,10 @@ def _interpolated_values(self, time_range, interval, filter_expression):
time_range, interval, filter_expression, include_filtered_values
)

def _update_value(self,value,update_option,buffer_option):
""" Internal function to write to pi point"""
return self.pi_point.UpdateValue(value,update_option,buffer_option)

def _summary(self, time_range, summary_types, calculation_basis, time_type):
return self.pi_point.Summary(
time_range, summary_types, calculation_basis, time_type
Expand Down
32 changes: 13 additions & 19 deletions PIconnect/PIAF.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,12 @@


class PIAFDatabase(object):
"""PIAFDatabase
"""Context manager for connections to the PI Asset Framework database."""

Context manager for connections to the PI Asset Framework database.
"""

version = "0.1.1"
version = "0.1.0"

servers = {
s.Name: {"server": s, "databases": {d.Name: d for d in s.Databases}}
for s in AF.PISystems()
}
if AF.PISystems().DefaultPISystem:
default_server = servers[AF.PISystems().DefaultPISystem.Name]
elif len(servers) > 0:
default_server = servers[list(servers)[0]]
else:
default_server = None
servers = {x.Name: {"server": x, "databases": {}} for x in AF.PISystems()}
default_server = servers[AF.PISystems().DefaultPISystem.Name]

def __init__(self, server=None, database=None):
self.server = None
Expand Down Expand Up @@ -105,10 +94,7 @@ def __enter__(self):
return self

def __exit__(self, *args):
pass
# Disabled disconnecting because garbage collection sometimes impedes
# connecting to another server later
# self.server.Disconnect()
self.server.Disconnect()

def __repr__(self):
return "%s(\\\\%s\\%s)" % (
Expand Down Expand Up @@ -257,6 +243,14 @@ def _interpolated_values(self, time_range, interval, filter_expression):
filter_expression,
include_filtered_values,
)

def _update_value(self,value,update_option,buffer_option):
""" Internal function to write to pi point"""
return self.attribute.Data.UpdateValue(
value,
update_option,
buffer_option
)

def _summary(self, time_range, summary_types, calculation_basis, time_type):
return self.attribute.Data.Summary(
Expand Down
45 changes: 33 additions & 12 deletions PIconnect/PIConsts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,6 @@
IntFlag = IntEnum


class AuthenticationMode(IntEnum):
"""AuthenticationMode indicates how a user authenticates to a PI Server

Detailed information is available at https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/T_OSIsoft_AF_PI_PIAuthenticationMode.htm
"""

#: Use Windows authentication when making a connection
WINDOWS_AUTHENTICATION = 0
#: Use the PI User authentication mode when making a connection
PI_USER_AUTHENTICATION = 1


class CalculationBasis(IntEnum):
"""CalculationBasis indicates how values should be weighted over a time range

Expand Down Expand Up @@ -108,7 +96,40 @@ class TimestampCalculation(IntEnum):
#: The timestamp is always the end of the interval.
MOST_RECENT_TIME = 2

class UpdateOption(IntEnum):
"""
Indicates how to treat duplicate values in the archive, when supported by the Data Reference

Detailed information is available at https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/T_OSIsoft_AF_Data_AFUpdateOption.htm
"""
# Add the value to the archive. If any values exist at the same time, will overwrite one of them and set its Substituted flag.
REPLACE = 0
# Add the value to the archive. Any existing values at the same time are not overwritten.
INSERT = 1
# Add the value to the archive only if no value exists at the same time. If a value already exists for that time, the passed value is ignored.
NOREPLACE = 2
# Replace an existing value in the archive at the specified time. If no existing value is found, the passed value is ignored.
REPLACEONLY = 3
# Add the value to the archive without compression. If this value is written to the snapshot, the previous snapshot value will be written to the archive,
# without regard to compression settings. Note that if a subsequent snapshot value is written without the InsertNoCompression option,
# the value added with the InsertNoCompression option is still subject to compression.
INSERTNOCOMPRESSION = 5
# Remove the value from the archive if a value exists at the passed time.
REMOVE = 6

class BufferOption(IntEnum):
"""
Indicates buffering option in updating values, when supported by the Data Reference.

Detailed information is available at https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/T_OSIsoft_AF_Data_AFBufferOption.htm
"""
# Updating data reference values without buffer.
DONOTBUFFER = 0
# Try updating data reference values with buffer. If fails (e.g. data reference AFDataMethods does not support Buffering, or its Buffering system is not available), then try updating directly without buffer.
BUFFERIFPOSSIBLE = 1
# Updating data reference values with buffer.
BUFFER = 2

def get_enumerated_value(enumeration, value, default):
if not value:
return default
Expand Down
Loading