@@ -66,8 +66,12 @@ def __init__(self, end_dest):
66
66
def send (self , message ):
67
67
""" Send message to Provider
68
68
"""
69
+ reply = None
69
70
with timeout (10 ):
70
71
self .connect ()
72
+
73
+ #try:
74
+
71
75
# send update
72
76
self ._Client__socket .send_string (message + '\0 ' ) # must include null byte
73
77
# get response
@@ -77,16 +81,25 @@ def send(self, message):
77
81
data = reply [1 ]
78
82
79
83
if status == self ._Client__kACK :
80
- print ( "I: ACK: " + data )
84
+ logger . info ( f "I: ACK -- { data } " )
81
85
#self.reply_handler(data)
82
86
else :
83
- print ("I: ERR -- %s" % msg )
87
+ logger .error (f"I: ERR -- { msg } " )
88
+
89
+ #finally:
90
+ # logger.debug(f"DEBUG: Closing socket and context...")
91
+ # self._Client__socket.close()
92
+ # self._Client__context.term()
93
+ # logger.debug(f"DEBUG: ... Closed socket and context")
84
94
95
+ try :
85
96
self ._Client__socket .close ()
86
97
self ._Client__context .term ()
98
+ except :
99
+ pass
87
100
88
- return reply
89
-
101
+ return reply
102
+
90
103
class alicanto ():
91
104
def __init__ (self , config , debug = False , exit_handler = None ):
92
105
@@ -101,16 +114,16 @@ def __init__(self, config, debug=False, exit_handler=None):
101
114
self .lock = threading .Lock ()
102
115
103
116
# Initialize system state
104
- self .state = {}
117
+ self .state = dict ()
105
118
# Tag=>destination map
106
- self .dests = {}
119
+ self .dests = dict ()
107
120
# Tag=>type map
108
- self .types = {}
109
- self .logic = {}
121
+ self .types = dict ()
122
+ self .logic = dict ()
110
123
# Expression parser for logic
111
124
self .parser = Parser ()
112
125
# Set of all tags
113
- self .tags = {}
126
+ self .tags = dict ()
114
127
115
128
############## Get counts from json ######################
116
129
cfg = None
@@ -133,7 +146,7 @@ def __init__(self, config, debug=False, exit_handler=None):
133
146
134
147
# Diagnostics to confirm JSON config correctly added the required
135
148
# endpoints and subscriptions
136
- self .endid = {}
149
+ self .endid = dict ()
137
150
self .end_dests = []
138
151
for i , endpoint in enumerate (cfg ["endpoints" ]):
139
152
self .endid [i ] = endpoint
@@ -149,7 +162,7 @@ def __init__(self, config, debug=False, exit_handler=None):
149
162
# make end_dests elements unique
150
163
self .end_dests = list (set (self .end_dests ))
151
164
152
- self .subid = {}
165
+ self .subid = dict ()
153
166
self .sub_sources = []
154
167
for i in range (0 , self .sub_count ):
155
168
self .subid [i ] = cfg ["subscriptions" ][i ]
@@ -185,16 +198,6 @@ def __init__(self, config, debug=False, exit_handler=None):
185
198
self .__sub_thread .daemon = True
186
199
self .__sub_thread .start ()
187
200
188
- self .end_clients = {}
189
- for end_dest in self .end_dests :
190
- # Initialize bennu Client
191
- end_dest = end_dest .split ('/' )[0 ]
192
- try :
193
- self .end_clients [end_dest ] = alicantoClient (end_dest )
194
- except :
195
- logger .error (f"\t Error Initializing Client: { self .end_clients } " )
196
- for key in list (self .end_clients .keys ()):
197
- logger .info (f"End_client: { key } " )
198
201
199
202
def run (self ):
200
203
############## Entering Execution Mode ##############################
@@ -212,17 +215,32 @@ def run(self):
212
215
end_dest_tag = (full_end_dest .split ('/' )[1 ]
213
216
if '/' in full_end_dest
214
217
else full_end_dest )
218
+
219
+ logger .info ("Reading initial value from client now..." )
220
+ try :
221
+ client = alicantoClient (end_dest )
222
+ except :
223
+ logger .error (f"\t Error Initializing Client: { client } " )
224
+ continue
225
+
226
+ try :
227
+ reply = client .send ("READ=" + end_dest_tag )
228
+ if not reply :
229
+ continue
230
+ except :
231
+ logger .error (f"\t Error Reading remote value" )
232
+ continue
233
+
215
234
try :
216
- self .end_clients [end_dest ] = alicantoClient (end_dest )
217
- reply = self .end_clients [end_dest ].send ("READ=" + end_dest_tag )
218
235
value = reply [1 ].rstrip ('\x00 ' )
219
236
self .endid [i ]["value" ] = value
220
- self .tag (full_end_dest , value )
237
+ self .set_tag (full_end_dest , value )
221
238
logger .debug (f"Initial Endpoints { end_name } / { end_dest } :{ value } " )
222
-
223
239
except :
224
- logger .error (f"\t Error Initializing Client: { self . end_clients } " )
240
+ logger .error (f"\t Error Parsing response from Client " )
225
241
continue
242
+
243
+ logger .info ("... Client value status initialized!" )
226
244
227
245
########## Main co-simulation loop ####################################
228
246
while True :
@@ -241,108 +259,112 @@ def run(self):
241
259
if '/' in full_end_dest
242
260
else full_end_dest )
243
261
244
- if self .types [full_end_name ] == 'float' or self .types [full_end_name ] == 'double' :
245
- if not math .isclose (float (self .tag (full_end_name )), float (self .tag (full_end_dest ))):
246
- #Handle Logic
247
- if self .logic [full_end_dest ] is not None :
248
- expr = self .parser .parse (self .logic [full_end_dest ])
249
- '''
250
- # Assign variables
251
- vars = {}
252
- for var in expr.variables():
253
- vars[var] = self.tag(var)
254
- '''
255
- i = 0
256
- # Assign vars not working, so assign token manually
257
- for token in expr .tokens :
258
- for search_tag in self .tags :
259
- if token .toString () == search_tag :
260
- expr .tokens [i ].number_ = self .tag (token .toString ())
261
- i += 1
262
- # Evaluate expression
263
- value = expr .evaluate (vars )
264
- value = str (value ).lower ()
265
- if value != self .tag (full_end_dest ):
266
- logger .debug (f"\t LOGIC: { full_end_dest .strip ()} ={ self .logic [full_end_dest ]} ----> { value } " )
267
- # Assign new tag value
268
- self .tag (full_end_dest , value )
269
- # Skip if value is unchanged
270
- elif value == self .tag (full_end_dest ):
271
- continue
272
-
273
- try :
274
- self .end_clients [end_dest ] = alicantoClient (end_dest )
275
- if self .logic [full_end_dest ] is not None :
276
- self .end_clients [end_dest ].write_analog_point (end_dest_tag , self .tag (full_end_dest ))
277
- else :
278
- self .end_clients [end_dest ].write_analog_point (end_dest_tag , self .tag (full_end_name ))
279
- time .sleep (0.5 )
280
- reply = self .end_clients [end_dest ].send ("READ=" + end_dest_tag )
281
- value = reply [1 ].rstrip ('\x00 ' )
282
- self .tag (full_end_dest , value )
283
- except :
284
- logger .error (f"\t Error Initializing Client: { self .end_clients } " )
285
- continue
286
- elif self .types [full_end_name ] == 'bool' :
287
- if str (self .tag (full_end_name )).lower () != str (self .tag (full_end_dest )).lower ():
288
- #Handle Logic
289
- if self .logic [full_end_dest ] is not None :
290
- expr = self .parser .parse (self .logic [full_end_dest ])
291
- '''
292
- # Assign variables
293
- vars = {}
294
- for var in expr.variables():
295
- vars[var] = self.tag(var)
296
- '''
297
- i = 0
298
- # Assign vars not working, so assign token manually
299
- for token in expr .tokens :
300
- for search_tag in self .tags :
301
- if token .toString () == search_tag :
302
- expr .tokens [i ].number_ = bool (self .tag (token .toString ()))
303
- i += 1
304
- # Evaluate expression
305
- value = expr .evaluate (vars )
306
- value = str (value )
307
- if value != self .tag (full_end_dest ):
308
- logger .debug (f"\t LOGIC: { full_end_dest .strip ()} ={ self .logic [full_end_dest ]} ----> { value } " )
309
- # Assign new tag value
310
- self .tag (full_end_dest , value )
311
- # Skip if value is unchanged
312
- elif value == self .tag (full_end_dest ):
313
- continue
314
- try :
315
- self .end_clients [end_dest ] = alicantoClient (end_dest )
316
- if self .logic [full_end_dest ] is not None :
317
- self .end_clients [end_dest ].write_digital_point (end_dest_tag , eval (self .tag (full_end_dest )))
318
- else :
319
- self .end_clients [end_dest ].write_digital_point (end_dest_tag , eval (self .tag (full_end_name )))
320
- time .sleep (0.5 )
321
- reply = self .end_clients [end_dest ].send ("READ=" + end_dest_tag )
322
- value = reply [1 ].rstrip ('\x00 ' )
323
- self .tag (full_end_dest , value )
324
- except :
325
- logger .error (f"\t Error Initializing Client: { self .end_clients } " )
326
- continue
262
+ these_types = self .types [full_end_name ]
263
+
264
+ # If we don't need to update the value, escape early
265
+ if (these_types == 'float' or these_types == 'double' ) and (math .isclose (float (self .get_tag (full_end_name )), float (self .get_tag (full_end_dest )))):
266
+ #logger.debug(f"SKIP: No need to update {self.get_tag(full_end_name)} vs {self.get_tag(full_end_dest)}")
267
+ continue
268
+ true_set = (True , 'True' , 'true' , '1' , 1 )
269
+ if (these_types == 'bool' ) and ((self .get_tag (full_end_name ) in true_set ) == (self .get_tag (full_end_dest ) in true_set )):
270
+ #logger.debug(f"SKIP: No need to update {self.get_tag(full_end_name)} vs {self.get_tag(full_end_dest)}")
271
+ continue
272
+
273
+ # Handle the case where there is logic involved
274
+ if self .logic [full_end_dest ] is not None :
275
+ expr = self .parser .parse (self .logic [full_end_dest ])
276
+
277
+ # Assign variables
278
+ these_vars = dict ()
279
+
280
+ '''
281
+ for v in expr.variables():
282
+ t = self.get_tag(v)
283
+ if these_types == 'bool':
284
+ t = bool(t)
285
+
286
+ these_vars[v] = t
287
+
288
+ '''
289
+ # Automatic variable parsing with expression parser not working, so assign token manually
290
+ for i ,token in enumerate (expr .tokens ):
291
+ if token .toString () in self .tags :
292
+ t = self .get_tag (token .toString ())
293
+ if these_types == 'bool' :
294
+ t = bool (t )
295
+
296
+ expr .tokens [i ].number_ = t
297
+
298
+ # Evaluate expression
299
+ value = expr .evaluate (these_vars )
300
+ value = str (value )
301
+ if value != self .get_tag (full_end_dest ):
302
+ self .set_tag (full_end_dest , value )
303
+ else :
304
+ continue
305
+
306
+ tag_ptr = full_end_dest
307
+
308
+ else :
309
+ tag_ptr = full_end_name
310
+
311
+
312
+ # Send update
313
+ logger .info (f"Sending value update..." )
314
+ try :
315
+ client = alicantoClient (end_dest )
316
+ except :
317
+ logger .error (f"\t Error Initializing Client: { client } " )
318
+ continue
319
+
320
+ try :
321
+ if these_types == 'float' or these_types == 'double' :
322
+ client .write_analog_point (end_dest_tag , self .get_tag (tag_ptr ))
323
+ elif these_types == 'bool' :
324
+ client .write_digital_point (end_dest_tag , eval (self .get_tag (tag_ptr )))
325
+ except :
326
+ logger .error (f"\t Error Writing value to remote Client" )
327
+
328
+ time .sleep (0.5 )
329
+
330
+ try :
331
+ reply = client .send ("READ=" + end_dest_tag )
332
+ if not reply :
333
+ continue
334
+ except :
335
+ logger .error (f"\t Error Reading remote value" )
336
+ continue
337
+
338
+ try :
339
+ value = reply [1 ].rstrip ('\x00 ' )
340
+ self .set_tag (full_end_dest , value )
341
+ except :
342
+ logger .error (f"\t Error Parsing response from Client" )
343
+ continue
344
+
345
+ logger .info (f"... Update sent!" )
346
+
327
347
328
348
def publish_state (self ):
329
349
logger .info ("=================== DATA ===================" )
330
350
for tag in self .tags :
331
- logger .info (f"{ tag :<30} --- { self .tag (tag ):} " )
351
+ logger .info (f"{ tag :<30} --- { self .get_tag (tag ):} " )
332
352
logger .info ("============================================" )
333
353
334
354
def get_type (self , tag ):
335
355
return self .types [tag ]
336
356
337
- def tag (self , tag , value = None ):
357
+ def get_tag (self , tag ):
358
+ with self .lock :
359
+ if tag in self .state :
360
+ return self .state [tag ]
361
+ else :
362
+ return False if self .get_type (tag ) == 'bool' else 0
363
+
364
+ def set_tag (self , tag , value = None ):
338
365
with self .lock :
339
366
if value is not None :
340
367
self .state [tag ] = value
341
- else :
342
- if tag in self .state :
343
- return self .state [tag ]
344
- else :
345
- return False if self .get_type (tag ) == 'bool' else 0
346
368
347
369
def _subscription_handler (self , message ):
348
370
"""Receive Subscription message
@@ -359,10 +381,8 @@ def _subscription_handler(self, message):
359
381
sub_source = threading .current_thread ().name
360
382
361
383
for point in points :
362
- if not point :
384
+ if not point or len ( point ) <= 1 :
363
385
continue
364
- if point == "" :
365
- continue
366
386
367
387
try :
368
388
tag = point .split (':' )[0 ]
@@ -386,21 +406,13 @@ def _subscription_handler(self, message):
386
406
field = 'value'
387
407
388
408
if field == 'value' :
389
- if not math .isclose (float (self .tag (full_tag )), value ):
390
- self .tag (full_tag , value )
391
- logger .debug ("UPDATE NOW: " + full_tag )
392
- logger .debug ("New value: " + str (value ))
393
- else :
394
- continue
409
+ if not math .isclose (float (self .get_tag (full_tag )), value ):
410
+ self .set_tag (full_tag , value )
411
+ logger .debug (f"UPDATE NOW: { full_tag } = { value } " )
395
412
elif field == 'status' :
396
- if self .tag (full_tag ) != value :
397
- self .tag (full_tag , value )
398
- logger .debug ("UPDATE NOW: " + full_tag )
399
- logger .debug ("New value: " + str (value ))
400
- else :
401
- continue
402
- else :
403
- continue
413
+ if self .get_tag (full_tag ) != value :
414
+ self .set_tag (full_tag , value )
415
+ logger .debug (f"UPDATE NOW: { full_tag } = { value } " )
404
416
405
417
def ctrl_exit_handler (self , signal , frame ):
406
418
logger .info ("SIGINT or CTRL-C detected. Exiting gracefully" )
@@ -423,4 +435,4 @@ def main():
423
435
try :
424
436
main ()
425
437
except KeyboardInterrupt :
426
- sys .exit ()
438
+ sys .exit ()
0 commit comments