Skip to content

Commit 0a8cd3a

Browse files
authored
Merge pull request #5 from PTCInc/EGD_Update
Egd update - Update to Beta 5
2 parents 0cba789 + f10c5ca commit 0a8cd3a

File tree

11 files changed

+1099
-2
lines changed

11 files changed

+1099
-2
lines changed

dist/kepconfig-1.0b5-py3-none-any.whl

38.5 KB
Binary file not shown.

dist/kepconfig-1.0b5.tar.gz

19.5 KB
Binary file not shown.

kepconfig/connection.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def reinitialize(self):
128128
return job
129129
except KepError.KepHTTPError as err:
130130
if err.code == 429:
131+
job = KepServiceResponse()
131132
job.code = err.code
132133
job.message = err.payload
133134
return job
@@ -261,6 +262,7 @@ def __connect(self,request_obj):
261262
data = _HttpDataAbstract()
262263
request_obj.add_header("Authorization", "Basic %s" % self.__build_auth_str(self.username, self.password))
263264
request_obj.add_header("Content-Type", "application/json")
265+
request_obj.add_header("Accept", "application/json")
264266
try:
265267
# context is sent regardless of HTTP or HTTPS - seems to be ignored if HTTP URL
266268
with request.urlopen(request_obj, context=self.__ssl_context) as server:
@@ -284,7 +286,8 @@ def __connect(self,request_obj):
284286
# Ex: Space will be turned to %20
285287
def __url_validate(self, url):
286288
parsed_url = parse.urlparse(url)
287-
updated_path = parse.quote(parsed_url.path)
289+
# Added % for scenarios where special characters have already been escaped with %
290+
updated_path = parse.quote(parsed_url.path, safe = '/%')
288291

289292
# If host is "localhost", force using the IPv4 loopback adapter IP address in all calls
290293
# This is done to remove retries that will happen when the host resolution uses IPv6 intially

kepconfig/connectivity/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66

77

88
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
9-
from . import channel, device, tag
9+
from . import channel, device, tag, egd

kepconfig/connectivity/device.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ def auto_tag_gen(server, device_path):
197197
return False
198198
except kepconfig.error.KepHTTPError as err:
199199
if err.code == 429:
200+
job = kepconfig.connection.KepServiceResponse()
200201
job.code = err.code
201202
job.message = err.payload
202203
return job
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) 2020, PTC Inc. and/or all its affiliates. All rights reserved.
3+
# See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
7+
8+
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
9+
from . import exchange, range, name
10+
11+
CONSUMER_EXCHANGE = 'CONSUMER'
12+
PRODUCER_EXCHANGE = 'PRODUCER'
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) PTC Inc. and/or all its affiliates. All rights reserved.
3+
# See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
7+
8+
# r""":mod:`exchange` exposes an API to allow modifications (add, delete, modify) to
9+
# exchange objects for EGD devices within the Kepware Configuration API
10+
# """
11+
12+
import kepconfig
13+
from typing import Union
14+
from .. import egd as EGD, channel, device
15+
16+
CONSUMER_ROOT = '/consumer_exchange_groups/consumer exchanges/consumer_exchanges'
17+
PRODUCER_ROOT = '/producer_exchange_groups/producer exchanges/producer_exchanges'
18+
19+
def _create_url(device_path, ex_type, exchange_name = None):
20+
'''Creates url object for the "exchange" branch of Kepware's project tree. Used
21+
to build a part of Kepware Configuration API URL structure
22+
23+
Returns the exchange specific url when a value is passed as the exchange name.
24+
'''
25+
path_obj = kepconfig.path_split(device_path)
26+
device_root = channel._create_url(path_obj['channel']) + device._create_url(path_obj['device'])
27+
28+
if exchange_name == None:
29+
if ex_type == EGD.CONSUMER_EXCHANGE:
30+
return device_root + CONSUMER_ROOT
31+
else:
32+
return device_root + PRODUCER_ROOT
33+
else:
34+
if ex_type == EGD.CONSUMER_EXCHANGE:
35+
return '{}{}/{}'.format(device_root,CONSUMER_ROOT,exchange_name)
36+
else:
37+
return '{}{}/{}'.format(device_root,PRODUCER_ROOT,exchange_name)
38+
39+
def add_exchange(server, device_path, ex_type, DATA) -> Union[bool, list]:
40+
'''Add a "exchange" or multiple "exchange" objects to Kepware. Can be used to pass children of a exchange object
41+
such as ranges. This allows you to create a exchange and ranges for the exchange all in one function, if desired.
42+
43+
Additionally it can be used to pass a list of exchanges and it's children to be added all at once.
44+
45+
INPUTS:
46+
47+
"server" - instance of the "server" class
48+
49+
"device_path" - path to exchanges. Standard Kepware address decimal
50+
notation string such as "channel1.device1"
51+
52+
"type" - type of exchange either consumer or producer
53+
54+
"DATA" - properly JSON object (dict) of the exchange and it's children
55+
expected by Kepware Configuration API
56+
57+
RETURNS:
58+
59+
True - If a "HTTP 201 - Created" is received from Kepware
60+
61+
List - If a "HTTP 207 - Multi-Status" is received from Kepware with a list of dict error responses for all
62+
exchanges added that failed.
63+
64+
False - If a non-expected "2xx successful" code is returned
65+
66+
67+
EXCEPTIONS:
68+
69+
KepHTTPError - If urllib provides an HTTPError
70+
KepURLError - If urllib provides an URLError
71+
'''
72+
73+
r = server._config_add(server.url + _create_url(device_path, ex_type), DATA)
74+
if r.code == 201: return True
75+
elif r.code == 207:
76+
errors = []
77+
for item in r.payload:
78+
if item['code'] != 201:
79+
errors.append(item)
80+
return errors
81+
else: return False
82+
83+
def del_exchange(server, device_path, ex_type, exchange_name) -> bool:
84+
'''Delete a "exchange" object in Kepware. This will delete all children as well
85+
86+
INPUTS:
87+
88+
"server" - instance of the "server" class
89+
90+
"device_path" - path to exchanges. Standard Kepware address decimal
91+
notation string such as "channel1.device1"
92+
93+
"ex_type" - type of exchange either consumer or producer
94+
95+
"exchange_name" - name of exchange
96+
97+
RETURNS:
98+
99+
True - If a "HTTP 200 - OK" is received from Kepware
100+
101+
EXCEPTIONS:
102+
103+
KepHTTPError - If urllib provides an HTTPError
104+
KepURLError - If urllib provides an URLError
105+
'''
106+
107+
r = server._config_del(server.url + _create_url(device_path, ex_type, exchange_name))
108+
if r.code == 200: return True
109+
else: return False
110+
111+
def modify_exchange(server, device_path, ex_type, DATA, exchange_name = None, force = False) -> bool:
112+
'''Modify a exchange object and it's properties in Kepware. If a "exchange_name" is not provided as an input,
113+
you need to identify the exchange in the 'common.ALLTYPES_NAME' property field in the "DATA". It will
114+
assume that is the exchange that is to be modified.
115+
116+
INPUTS:
117+
118+
"server" - instance of the "server" class
119+
120+
"device_path" - path to exchanges. Standard Kepware address decimal
121+
notation string such as "channel1.device1"
122+
123+
"ex_type" - type of exchange either consumer or producer
124+
125+
"DATA" - properly JSON object (dict) of the exchange properties to be modified.
126+
127+
"exchange_name" (optional) - name of exchange to modify. Only needed if not existing in "DATA"
128+
129+
"force" (optional) - if True, will force the configuration update to the Kepware server
130+
131+
RETURNS:
132+
133+
True - If a "HTTP 200 - OK" is received from Kepware
134+
135+
EXCEPTIONS:
136+
137+
KepHTTPError - If urllib provides an HTTPError
138+
KepURLError - If urllib provides an URLError
139+
'''
140+
141+
exchange_data = server._force_update_check(force, DATA)
142+
if exchange_name == None:
143+
try:
144+
r = server._config_update(server.url + _create_url(device_path, ex_type, exchange_data['common.ALLTYPES_NAME']), exchange_data)
145+
if r.code == 200: return True
146+
else: return False
147+
except KeyError as err:
148+
print('Error: No exchange identified in DATA | Key Error: {}'.format(err))
149+
return False
150+
# except Exception as e:
151+
# return 'Error: Error with {}: {}'.format(inspect.currentframe().f_code.co_name, str(e))
152+
else:
153+
r = server._config_update(server.url + _create_url(device_path, ex_type, exchange_name), exchange_data)
154+
if r.code == 200: return True
155+
else: return False
156+
157+
def get_exchange(server, device_path, ex_type, exchange_name = None) -> Union[dict, list]:
158+
'''Returns the properties of the exchange object or a list of all exchanges and their
159+
properties for the type input. Returned object is JSON.
160+
161+
INPUTS:
162+
163+
"server" - instance of the "server" class
164+
165+
"device_path" - path to exchanges. Standard Kepware address decimal
166+
notation string such as "channel1.device1"
167+
168+
"ex_type" - type of exchange either consumer or producer
169+
170+
"exchange_name" - name of exchange
171+
172+
RETURNS:
173+
174+
JSON - data for the exchange requested or a list of exchanges and their properties
175+
176+
EXCEPTIONS:
177+
178+
KepHTTPError - If urllib provides an HTTPError
179+
KepURLError - If urllib provides an URLError
180+
'''
181+
if exchange_name == None:
182+
r = server._config_get(server.url + _create_url(device_path, ex_type))
183+
else:
184+
r = server._config_get(server.url + _create_url(device_path, ex_type, exchange_name))
185+
return r.payload
186+
187+
def get_all_exchanges(server, device_path):
188+
'''Returns list of all exchange objects and their properties. Returned object is JSON list.
189+
190+
INPUTS:
191+
192+
"server" - instance of the "server" class
193+
194+
"device_path" - path to exchanges. Standard Kepware address decimal
195+
notation string such as "channel1.device1"
196+
197+
RETURNS:
198+
199+
List - [list of consumer exchanges, list of producer exchanges] - list of lists for all
200+
exchanges for the device
201+
202+
EXCEPTIONS:
203+
204+
KepHTTPError - If urllib provides an HTTPError
205+
KepURLError - If urllib provides an URLError
206+
'''
207+
exchange_list = []
208+
exchange_list.append(get_exchange(server, device_path, EGD.CONSUMER_EXCHANGE))
209+
exchange_list.append(get_exchange(server, device_path, EGD.PRODUCER_EXCHANGE))
210+
return exchange_list

0 commit comments

Comments
 (0)