pymscada 0.0.14__py3-none-any.whl → 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pymscada might be problematic. Click here for more details.

@@ -84,4 +84,450 @@ pages:
84
84
  - name: Files
85
85
  parent: Dropdown
86
86
  items:
87
- - {tagname: __files__, type: files}
87
+ - {tagname: __files__, type: files}
88
+ - name: Temperature
89
+ parent: Weather
90
+ items:
91
+ - type: uplot # Do all times in seconds, which uplot uses.
92
+ ms:
93
+ desc: Temperature
94
+ age: 172800
95
+ legend_pos: left
96
+ time_pos: left
97
+ time_res: m
98
+ axes:
99
+ - scale: x
100
+ range: [-604800, 86400] # 86400 172800 1209600
101
+ - scale: 'C'
102
+ range: [0.0, 35.0]
103
+ dp: 1
104
+ series:
105
+ - tagname: temperature
106
+ label: Current Temperature
107
+ scale: 'C'
108
+ color: black
109
+ width: 2
110
+ dp: 1
111
+ - tagname: temperature_01
112
+ label: 1h Temperature
113
+ scale: 'C'
114
+ color: darkgray
115
+ width: 1.5
116
+ dp: 1
117
+ - tagname: temperature_04
118
+ label: 4h Temperature
119
+ scale: 'C'
120
+ color: green
121
+ width: 1
122
+ dp: 1
123
+ - tagname: temperature_12
124
+ label: 12h Temperature
125
+ scale: 'C'
126
+ color: orange
127
+ width: 0.75
128
+ dp: 1
129
+ - tagname: temperature_24
130
+ label: 24h Temperature
131
+ scale: 'C'
132
+ color: red
133
+ width: 0.5
134
+ dp: 1
135
+ - name: Wind Speed
136
+ parent: Weather
137
+ items:
138
+ - type: uplot # Do all times in seconds, which uplot uses.
139
+ ms:
140
+ desc: Wind Speed
141
+ age: 172800
142
+ legend_pos: left
143
+ time_pos: left
144
+ time_res: m
145
+ axes:
146
+ - scale: x
147
+ range: [-604800, 86400] # 86400 172800 1209600
148
+ - scale: 'm/s'
149
+ range: [0.0, 20.0]
150
+ dp: 1
151
+ series:
152
+ - tagname: windSpeed
153
+ label: Current Wind Speed
154
+ scale: 'm/s'
155
+ color: black
156
+ width: 2
157
+ dp: 1
158
+ - tagname: windSpeed_01
159
+ label: 1h Wind Speed
160
+ scale: 'm/s'
161
+ color: darkgray
162
+ width: 1.5
163
+ dp: 1
164
+ - tagname: windSpeed_04
165
+ label: 4h Wind Speed
166
+ scale: 'm/s'
167
+ color: green
168
+ width: 1
169
+ dp: 1
170
+ - tagname: windSpeed_12
171
+ label: 12h Wind Speed
172
+ scale: 'm/s'
173
+ color: orange
174
+ width: 0.75
175
+ dp: 1
176
+ - tagname: windSpeed_24
177
+ label: 24h Wind Speed
178
+ scale: 'm/s'
179
+ color: red
180
+ width: 0.5
181
+ dp: 1
182
+ - name: Wind Direction
183
+ parent: Weather
184
+ items:
185
+ - type: uplot # Do all times in seconds, which uplot uses.
186
+ ms:
187
+ desc: Wind Direction
188
+ age: 172800
189
+ legend_pos: left
190
+ time_pos: left
191
+ time_res: m
192
+ axes:
193
+ - scale: x
194
+ range: [-604800, 86400] # 86400 172800 1209600
195
+ - scale: 'deg'
196
+ range: [0.0, 360.0]
197
+ dp: 1
198
+ series:
199
+ - tagname: windDirection
200
+ label: Current Wind Direction
201
+ scale: 'deg'
202
+ color: black
203
+ width: 2
204
+ dp: 1
205
+ - tagname: windDirection_01
206
+ label: 1h Wind Direction
207
+ scale: 'deg'
208
+ color: darkgray
209
+ width: 1.5
210
+ dp: 1
211
+ - tagname: windDirection_04
212
+ label: 4h Wind Direction
213
+ scale: 'deg'
214
+ color: green
215
+ width: 1
216
+ dp: 1
217
+ - tagname: windDirection_12
218
+ label: 12h Wind Direction
219
+ scale: 'deg'
220
+ color: orange
221
+ width: 0.75
222
+ dp: 1
223
+ - tagname: windDirection_24
224
+ label: 24h Wind Direction
225
+ scale: 'deg'
226
+ color: red
227
+ width: 0.5
228
+ dp: 1
229
+ - name: Rain Accumulation
230
+ parent: Weather
231
+ items:
232
+ - type: uplot # Do all times in seconds, which uplot uses.
233
+ ms:
234
+ desc: Rain Accumulation
235
+ age: 172800
236
+ legend_pos: left
237
+ time_pos: left
238
+ time_res: m
239
+ axes:
240
+ - scale: x
241
+ range: [-604800, 86400] # 86400 172800 1209600
242
+ - scale: 'mm'
243
+ range: [0.0, 10.0]
244
+ dp: 1
245
+ series:
246
+ - tagname: rainAccumulation
247
+ label: Current Rain Accumulation
248
+ scale: 'mm'
249
+ color: black
250
+ width: 2
251
+ dp: 1
252
+ - tagname: rainAccumulation_01
253
+ label: 1h Rain Accumulation
254
+ scale: 'mm'
255
+ color: darkgray
256
+ width: 1.5
257
+ dp: 1
258
+ - tagname: rainAccumulation_04
259
+ label: 4h Rain Accumulation
260
+ scale: 'mm'
261
+ color: green
262
+ width: 1
263
+ dp: 1
264
+ - tagname: rainAccumulation_12
265
+ label: 12h Rain Accumulation
266
+ scale: 'mm'
267
+ color: orange
268
+ width: 0.75
269
+ dp: 1
270
+ - tagname: rainAccumulation_24
271
+ label: 24h Rain Accumulation
272
+ scale: 'mm'
273
+ color: red
274
+ width: 0.5
275
+ dp: 1
276
+ - name: Humidity
277
+ parent: Weather
278
+ items:
279
+ - type: uplot # Do all times in seconds, which uplot uses.
280
+ ms:
281
+ desc: Humidity
282
+ age: 172800
283
+ legend_pos: left
284
+ time_pos: left
285
+ time_res: m
286
+ axes:
287
+ - scale: x
288
+ range: [-604800, 86400] # 86400 172800 1209600
289
+ - scale: '%'
290
+ range: [0.0, 100.0]
291
+ dp: 1
292
+ series:
293
+ - tagname: humidity
294
+ label: Current Humidity
295
+ scale: '%'
296
+ color: black
297
+ width: 2
298
+ dp: 1
299
+ - tagname: humidity_01
300
+ label: 1h Humidity
301
+ scale: '%'
302
+ color: darkgray
303
+ width: 1.5
304
+ dp: 1
305
+ - tagname: humidity_04
306
+ label: 4h Humidity
307
+ scale: '%'
308
+ color: green
309
+ width: 1
310
+ dp: 1
311
+ - tagname: humidity_12
312
+ label: 12h Humidity
313
+ scale: '%'
314
+ color: orange
315
+ width: 0.75
316
+ dp: 1
317
+ - tagname: humidity_24
318
+ label: 24h Humidity
319
+ scale: '%'
320
+ color: red
321
+ width: 0.5
322
+ dp: 1
323
+ - name: Values
324
+ parent: Weather
325
+ items:
326
+ - {tagname: temperature, type: value}
327
+ - {tagname: temperature_01, type: value}
328
+ - {tagname: temperature_04, type: value}
329
+ - {tagname: temperature_12, type: value}
330
+ - {tagname: temperature_24, type: value}
331
+ - {tagname: windSpeed, type: value}
332
+ - {tagname: windSpeed_01, type: value}
333
+ - {tagname: windSpeed_04, type: value}
334
+ - {tagname: windSpeed_12, type: value}
335
+ - {tagname: windSpeed_24, type: value}
336
+ - {tagname: windDirection, type: value}
337
+ - {tagname: windDirection_01, type: value}
338
+ - {tagname: windDirection_04, type: value}
339
+ - {tagname: windDirection_12, type: value}
340
+ - {tagname: windDirection_24, type: value}
341
+ - {tagname: rainAccumulation, type: value}
342
+ - {tagname: rainAccumulation_01, type: value}
343
+ - {tagname: rainAccumulation_04, type: value}
344
+ - {tagname: rainAccumulation_12, type: value}
345
+ - {tagname: rainAccumulation_24, type: value}
346
+ - {tagname: humidity, type: value}
347
+ - {tagname: humidity_01, type: value}
348
+ - {tagname: humidity_04, type: value}
349
+ - {tagname: humidity_12, type: value}
350
+ - {tagname: humidity_24, type: value}
351
+ - name: Logix
352
+ items:
353
+ - {tagname: Ani_Fin_20, type: setpoint}
354
+ - {tagname: Ani_Fout_20, type: value}
355
+ - {tagname: Ani_Iin_20, type: setpoint}
356
+ - {tagname: Ani_Iout_20, type: value}
357
+ - {tagname: InVar, type: setpoint}
358
+ - {tagname: OutVar, type: value}
359
+ - {tagname: Ani_Iin_21_0, type: setpoint}
360
+ - {tagname: Ani_Iout_21_0, type: value}
361
+ - {tagname: Ani_Iin_21_1, type: setpoint}
362
+ - {tagname: Ani_Iout_21_1, type: value}
363
+ - name: Values
364
+ parent: SNMP
365
+ items:
366
+ - {tagname: Router_eth1_bytes_in, type: value}
367
+ - {tagname: Router_eth1_bytes_out, type: value}
368
+ - {tagname: Router_eth2_bytes_in, type: value}
369
+ - {tagname: Router_eth2_bytes_out, type: value}
370
+ - {tagname: Router_eth3_bytes_in, type: value}
371
+ - {tagname: Router_eth3_bytes_out, type: value}
372
+ - {tagname: Router_eth4_bytes_in, type: value}
373
+ - {tagname: Router_eth4_bytes_out, type: value}
374
+ - {tagname: Router_eth5_bytes_in, type: value}
375
+ - {tagname: Router_eth5_bytes_out, type: value}
376
+ - {tagname: Router_eth6_bytes_in, type: value}
377
+ - {tagname: Router_eth6_bytes_out, type: value}
378
+ - {tagname: Router_eth7_bytes_in, type: value}
379
+ - {tagname: Router_eth7_bytes_out, type: value}
380
+ - {tagname: Router_eth8_bytes_in, type: value}
381
+ - {tagname: Router_eth8_bytes_out, type: value}
382
+ - name: Trend
383
+ parent: SNMP
384
+ items:
385
+ - type: uplot # Do all times in seconds, which uplot uses.
386
+ ms:
387
+ desc: Bytes
388
+ age: 172800
389
+ legend_pos: left
390
+ time_pos: left
391
+ time_res: m
392
+ axes:
393
+ - scale: x
394
+ range: [-86400, 0]
395
+ - scale: 'bytes'
396
+ range: [0, 100000]
397
+ dp: 0
398
+ series:
399
+ - tagname: Router_eth1_bytes_in
400
+ label: eth1 in
401
+ scale: 'bytes'
402
+ color: violet
403
+ width: 1
404
+ dp: 0
405
+ - tagname: Router_eth1_bytes_out
406
+ label: eth1 out
407
+ scale: 'bytes'
408
+ color: violet
409
+ width: 0.5
410
+ dp: 0
411
+ - tagname: Router_eth2_bytes_in
412
+ label: eth2 in
413
+ scale: 'bytes'
414
+ color: blue
415
+ width: 1
416
+ dp: 0
417
+ - tagname: Router_eth2_bytes_out
418
+ label: eth2 out
419
+ scale: 'bytes'
420
+ color: blue
421
+ width: 0.5
422
+ dp: 0
423
+ - tagname: Router_eth3_bytes_in
424
+ label: eth3 in
425
+ scale: 'bytes'
426
+ color: green
427
+ width: 1
428
+ dp: 0
429
+ - tagname: Router_eth3_bytes_out
430
+ label: eth3 out
431
+ scale: 'bytes'
432
+ color: green
433
+ width: 0.5
434
+ dp: 0
435
+ - tagname: Router_eth4_bytes_in
436
+ label: eth4 in
437
+ scale: 'bytes'
438
+ color: gray
439
+ width: 1
440
+ dp: 0
441
+ - tagname: Router_eth4_bytes_out
442
+ label: eth4 out
443
+ scale: 'bytes'
444
+ color: gray
445
+ width: 0.5
446
+ dp: 0
447
+ - tagname: Router_eth5_bytes_in
448
+ label: eth5 in
449
+ scale: 'bytes'
450
+ color: goldenrod
451
+ width: 1
452
+ dp: 0
453
+ - tagname: Router_eth5_bytes_out
454
+ label: eth5 out
455
+ scale: 'bytes'
456
+ color: goldenrod
457
+ width: 0.5
458
+ dp: 0
459
+ - tagname: Router_eth6_bytes_in
460
+ label: eth6 in
461
+ scale: 'bytes'
462
+ color: brown
463
+ width: 1
464
+ dp: 0
465
+ - tagname: Router_eth6_bytes_out
466
+ label: eth6 out
467
+ scale: 'bytes'
468
+ color: brown
469
+ width: 0.5
470
+ dp: 0
471
+ - tagname: Router_eth7_bytes_in
472
+ label: eth7 in
473
+ scale: 'bytes'
474
+ color: orange
475
+ width: 1
476
+ dp: 0
477
+ - tagname: Router_eth7_bytes_out
478
+ label: eth7 out
479
+ scale: 'bytes'
480
+ color: orange
481
+ width: 0.5
482
+ dp: 0
483
+ - tagname: Router_eth8_bytes_in
484
+ label: eth8 in
485
+ scale: 'bytes'
486
+ color: aqua
487
+ width: 1
488
+ dp: 0
489
+ - tagname: Router_eth8_bytes_out
490
+ label: eth8 out
491
+ scale: 'bytes'
492
+ color: aqua
493
+ width: 0.5
494
+ dp: 0
495
+ - name: Ping Values
496
+ parent: Ping
497
+ items:
498
+ - {desc: Default tags, type: h1}
499
+ - {tagname: localhost_ping, type: value}
500
+ - {tagname: google_ping, type: value}
501
+ - {tagname: electronet_ping, type: value}
502
+ - name: Ping Trend
503
+ parent: Ping
504
+ items:
505
+ - type: uplot # Do all times in seconds, which uplot uses.
506
+ ms:
507
+ desc: Ping Trend
508
+ age: 172800
509
+ legend_pos: left
510
+ time_pos: left
511
+ time_res: m
512
+ axes:
513
+ - scale: x
514
+ range: [-86400, 0] # 86400 172800 1209600
515
+ - scale: mS
516
+ range: [0.0, 1.0]
517
+ dp: 1
518
+ series:
519
+ - tagname: localhost_ping
520
+ label: localhost
521
+ scale: mS
522
+ color: black
523
+ dp: 1
524
+ - tagname: electronet_ping
525
+ label: electronet
526
+ scale: mS
527
+ color: blue
528
+ dp: 1
529
+ - tagname: google_ping
530
+ label: google
531
+ scale: mS
532
+ color: red
533
+ dp: 1
@@ -7,23 +7,22 @@ from pymscada.iodrivers.logix_map import LogixMaps
7
7
 
8
8
 
9
9
  class LogixClientConnector:
10
- """Poll Logix device, write on change in write range."""
10
+ """Manage interface to device."""
11
11
 
12
- def __init__(self, name: str, ip:str, rate: float, read: list,
13
- writeok: list, mapping: LogixMaps):
12
+ def __init__(self, name: str, ip: str, rate: float, poll: list,
13
+ mapping: LogixMaps):
14
14
  """Set up polling client."""
15
15
  self.plc_name = name
16
16
  self.ip = ip
17
17
  self.read_tags = []
18
- for r in read:
18
+ for r in poll:
19
19
  tag = r['addr']
20
20
  if r['type'].endswith('[]'):
21
21
  count = r['end'] - r['start'] + 1
22
22
  tag = f"{r['addr']}[{r['start']}]{{{count}}}"
23
23
  self.read_tags.append(tag)
24
24
  self.mapping = mapping
25
- self.mapping.add_write_callback(name, writeok,
26
- self.write_tag_update)
25
+ self.mapping.add_write_callback(name, self.write_tag_update)
27
26
  self.periodic = Periodic(self.poll, rate)
28
27
  self.plc = LogixDriver(ip)
29
28
 
@@ -33,14 +32,14 @@ class LogixClientConnector:
33
32
  logging.warning(f'write failed {self.plc_name} {addr} to {value}')
34
33
  return
35
34
  logging.info(f'writing {addr} {value}')
36
- res = self.plc.write((addr, value))
37
- pass
35
+ result = self.plc.write((addr, value))
36
+ logging.info(result)
38
37
 
39
38
  async def poll(self):
40
39
  """Poll data, reopen connection if dead."""
41
40
  if not self.plc.connected and not self.plc.open():
42
41
  return
43
- polled_tags = None
42
+ # polled_tags = None
44
43
  polled_tags = self.plc.read(*self.read_tags)
45
44
  self.mapping.polled_data(self.plc_name, polled_tags)
46
45
 
@@ -50,6 +49,7 @@ class LogixClientConnector:
50
49
 
51
50
 
52
51
  class LogixClient:
52
+ """Manage interface between bus and individual devices."""
53
53
 
54
54
  def __init__(self, bus_ip: str = '127.0.0.1', bus_port: int = 1324,
55
55
  rtus: dict = {}, tags: dict = {}) -> None:
@@ -12,52 +12,75 @@ DTYPES = {
12
12
  }
13
13
 
14
14
 
15
+ def tag_split(plc_tag: str):
16
+ """Split the address into rtu, variable, element and bit."""
17
+ separator = plc_tag.find(':')
18
+ arr_start_loc = plc_tag.find('[')
19
+ arr_end_loc = plc_tag.find(']')
20
+ bit_loc = plc_tag.find('.')
21
+ plc = plc_tag[:separator]
22
+ if arr_start_loc == -1 and bit_loc == -1:
23
+ var = plc_tag[separator + 1:]
24
+ elm = None
25
+ bit = None
26
+ elif arr_start_loc == -1:
27
+ var = plc_tag[separator + 1:bit_loc]
28
+ elm = None
29
+ bit = int(plc_tag[bit_loc + 1:])
30
+ elif bit_loc == -1:
31
+ var = plc_tag[separator + 1:arr_start_loc]
32
+ elm = int(plc_tag[arr_start_loc + 1:arr_end_loc])
33
+ bit = None
34
+ else:
35
+ var = plc_tag[separator + 1:arr_start_loc]
36
+ elm = int(plc_tag[arr_start_loc + 1:arr_end_loc])
37
+ bit = int(plc_tag[bit_loc + 1:])
38
+ return plc, var, elm, bit
39
+
40
+
15
41
  class LogixMap:
16
42
  """Do value updates for each tag."""
17
43
 
18
- def __init__(self, tagname: str, src_type: str, plc_tag: str):
44
+ def __init__(self, tagname: str, tagdict: dict):
19
45
  """Initialise modbus map and Tag."""
20
- dtype, dmin, dmax = DTYPES[src_type][0:3]
46
+ dtype, dmin, dmax = DTYPES[tagdict['type']][0:3]
21
47
  self.tag = Tag(tagname, dtype)
22
48
  self.map_bus = id(self)
23
- separator = plc_tag.find(':')
24
- arr_start_loc = plc_tag.find('[')
25
- arr_end_loc = plc_tag.find(']')
26
- bit_loc = plc_tag.find('.')
27
- self.plc = plc_tag[:separator]
28
- if arr_start_loc == -1 and bit_loc == -1:
29
- self.var = plc_tag[separator + 1:]
30
- self.elm = None
31
- self.bit = None
32
- elif arr_start_loc == -1:
33
- self.var = plc_tag[separator + 1:bit_loc]
34
- self.elm = None
35
- self.bit = int(plc_tag[bit_loc + 1:])
36
- elif bit_loc == -1:
37
- self.var = plc_tag[separator + 1:arr_start_loc]
38
- self.elm = int(plc_tag[arr_start_loc + 1:arr_end_loc])
39
- self.bit = None
40
- else:
41
- self.var = plc_tag[separator + 1:arr_start_loc]
42
- self.elm = int(plc_tag[arr_start_loc + 1:arr_end_loc])
43
- self.bit = int(plc_tag[bit_loc + 1:])
44
- self.plc_tag = plc_tag
45
- self.callback = None
46
49
  if dmin is not None:
47
50
  self.tag.value_min = dmin
48
51
  if dmax is not None:
49
52
  self.tag.value_max = dmax
50
- self.write_cb = None # used?
53
+ if 'read' in tagdict:
54
+ self.plc_read_tag = tagdict['read']
55
+ self.read_plc, self.read_var, self.read_elm, self.read_bit = \
56
+ tag_split(self.plc_read_tag)
57
+ else:
58
+ self.plc_read_tag = None
59
+ self.read_plc = None
60
+ self.read_var = None
61
+ self.read_elm = None
62
+ self.read_bit = None
63
+ if 'write' in tagdict:
64
+ self.plc_write_tag = tagdict['write']
65
+ self.write_plc, self.write_var, self.write_elm, self.write_bit = \
66
+ tag_split(self.plc_write_tag)
67
+ else:
68
+ self.plc_write_tag = None
69
+ self.write_plc = None
70
+ self.write_var = None
71
+ self.write_elm = None
72
+ self.write_bit = None
73
+ self.write_callback = None
51
74
 
52
75
  def set_callback(self, callback):
53
76
  """Add tag callback interface."""
54
- self.callback = callback
77
+ self.write_callback = callback
55
78
  self.tag.add_callback(self.tag_value_changed, bus_id=self.map_bus)
56
79
 
57
80
  def set_tag_value(self, value, time_us):
58
81
  """Pass update from IO driver to tag value."""
59
- if self.bit is not None:
60
- if value & 1 << self.bit:
82
+ if self.read_bit is not None:
83
+ if value & 1 << self.read_bit:
61
84
  value = 1
62
85
  else:
63
86
  value = 0
@@ -66,15 +89,15 @@ class LogixMap:
66
89
 
67
90
  def tag_value_changed(self, tag: Tag):
68
91
  """Pass update from tag value to IO driver."""
69
- if self.elm is None and self.bit is None:
70
- addr = self.var
71
- elif self.elm is None:
72
- addr = f'{self.var}.{self.bit}'
73
- elif self.bit is None:
74
- addr = f'{self.var}[{self.elm}]'
92
+ if self.write_elm is None and self.write_bit is None:
93
+ addr = self.write_var
94
+ elif self.write_elm is None:
95
+ addr = f'{self.write_var}.{self.write_bit}'
96
+ elif self.write_bit is None:
97
+ addr = f'{self.write_var}[{self.write_elm}]'
75
98
  else:
76
- addr = f'{self.var}[{self.elm}].{self.bit}'
77
- self.callback(addr, tag.value)
99
+ addr = f'{self.write_var}[{self.write_elm}].{self.write_bit}'
100
+ self.write_callback(addr, tag.value)
78
101
 
79
102
 
80
103
  class LogixMaps:
@@ -85,32 +108,21 @@ class LogixMaps:
85
108
  # use the tagname to access the map.
86
109
  self.tag_map: dict[str, LogixMap] = {}
87
110
  # use the plc_name then variable name to access a list of maps.
88
- self.var_map: dict[str, dict[str, list[LogixMap]]] = {}
89
- for tagname, v in tags.items():
90
- addr = v['addr']
91
- map = LogixMap(tagname, v['type'], addr)
92
- if map.plc not in self.var_map:
93
- self.var_map[map.plc] = {}
94
- if map.var not in self.var_map[map.plc]:
111
+ self.read_var_map: dict[str, dict[str, list[LogixMap]]] = {}
112
+ for tagname, tagdict in tags.items():
113
+ map = LogixMap(tagname, tagdict)
114
+ if map.read_plc not in self.read_var_map:
115
+ self.read_var_map[map.read_plc] = {}
116
+ if map.read_var not in self.read_var_map[map.read_plc]:
95
117
  # make a list so multiple bits can map to a word
96
- self.var_map[map.plc][map.var] = []
97
- self.var_map[map.plc][map.var].append(map)
118
+ self.read_var_map[map.read_plc][map.read_var] = []
119
+ self.read_var_map[map.read_plc][map.read_var].append(map)
98
120
  self.tag_map[map.tag.name] = map
99
121
 
100
- def add_write_callback(self, plcname, writeok, callback):
101
- """Connection advises device links."""
102
- # Create a set of all possible valid addresses
103
- write_set = set()
104
- for w in writeok:
105
- if '[' in w['type']:
106
- for i in range(w['start'], w['end'] + 1):
107
- write_set.add((w['addr'], i))
108
- else:
109
- write_set.add((w['addr'], None))
110
- # where the mapped tag uses a valid address, add callback to
111
- # the connection writer
122
+ def add_write_callback(self, plcname, callback):
123
+ """Register connector with map for write tags."""
112
124
  for map in self.tag_map.values():
113
- if map.plc == plcname and (map.var, map.elm) in write_set:
125
+ if map.write_plc == plcname:
114
126
  map.set_callback(callback)
115
127
 
116
128
  def polled_data(self, plcname, polls):
@@ -121,12 +133,12 @@ class LogixMaps:
121
133
  logging.error(poll.error)
122
134
  arr_start_loc = poll.tag.find('[')
123
135
  if arr_start_loc == -1:
124
- for map in self.var_map[plcname][poll.tag]:
136
+ for map in self.read_var_map[plcname][poll.tag]:
125
137
  map.set_tag_value(poll.value, time_us)
126
138
  else:
127
139
  var = poll.tag[:arr_start_loc]
128
140
  elm = int(poll.tag[arr_start_loc + 1: -1])
129
- for map in self.var_map[plcname][var]:
130
- elm_offset = map.elm - elm
141
+ for map in self.read_var_map[plcname][var]:
142
+ elm_offset = map.read_elm - elm
131
143
  if elm_offset > 0 and elm_offset < len(poll.value):
132
144
  map.set_tag_value(poll.value[elm_offset], time_us)