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