pymscada 0.1.0a1__py3-none-any.whl → 0.1.0a4__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.

pymscada/checkout.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Create base config folder and check out demo files."""
2
+ import difflib
2
3
  from pathlib import Path
3
4
  import sys
4
5
  from pymscada.config import get_demo_files, get_pdf_files
@@ -36,7 +37,7 @@ def make_pdf():
36
37
  target.write_bytes(pdf_file.read_bytes())
37
38
 
38
39
 
39
- def make_config(overwrite):
40
+ def make_config(overwrite: bool):
40
41
  """Make the config folder, if missing, and copy files in."""
41
42
  config_dir = PATH['__DIR__'].joinpath('config')
42
43
  if not config_dir.exists():
@@ -62,11 +63,43 @@ def make_config(overwrite):
62
63
  target.write_bytes(config_file.read_bytes())
63
64
 
64
65
 
65
- def checkout(overwrite=False):
66
+ def read_with_subst(file: Path):
67
+ """Read the file and replace DIR markers."""
68
+ rd = file.read_bytes().decode()
69
+ if str(file).endswith('service'):
70
+ for k, v in PATH.items():
71
+ rd = rd.replace(k, str(v.absolute()))
72
+ lines = rd.splitlines()
73
+ return lines
74
+
75
+
76
+ def compare_config():
77
+ """Compare old and new config."""
78
+ config_dir = PATH['__DIR__'].joinpath('config')
79
+ if not config_dir.exists():
80
+ print('No config dir, are you in the right directory')
81
+ return
82
+ for config_file in get_demo_files():
83
+ target = config_dir.joinpath(config_file.name)
84
+ if target.exists():
85
+ new_lines = read_with_subst(config_file)
86
+ old_lines = read_with_subst(target)
87
+ diff = list(difflib.unified_diff(old_lines, new_lines,
88
+ fromfile=str(target), tofile=str(config_file)))
89
+ if len(diff):
90
+ print('\n'.join(diff), '\n')
91
+ else:
92
+ print(f'\n--- MISSING FILE\n\n+++ {config_file}')
93
+
94
+
95
+ def checkout(overwrite=False, diff=False):
66
96
  """Do it."""
67
97
  for name in PATH:
68
98
  if not PATH[name].exists():
69
99
  raise SystemExit(f'{PATH[name]} is missing')
70
- make_history()
71
- make_pdf()
72
- make_config(overwrite)
100
+ if diff:
101
+ compare_config()
102
+ else:
103
+ make_history()
104
+ make_pdf(diff)
105
+ make_config(overwrite, diff)
@@ -7,10 +7,18 @@ rtus:
7
7
  tcp_udp: tcp
8
8
  serve:
9
9
  - {unit: 1, file: 4x, start: 1, end: 100}
10
+ - {unit: 2, file: 4x, start: 1, end: 100}
11
+ - {unit: 3, file: 4x, start: 1, end: 100}
10
12
  tags:
11
13
  sim_IntSet:
12
14
  type: int16
13
15
  addr: RTU:1:4x:1
16
+ sim_IntSet2:
17
+ type: int16
18
+ addr: RTU:2:4x:1
19
+ sim_IntSet3:
20
+ type: int16
21
+ addr: RTU:3:4x:1
14
22
  sim_IntVal:
15
23
  type: int16
16
24
  addr: RTU:1:4x:2
@@ -0,0 +1,12 @@
1
+ bus_ip: 127.0.0.1
2
+ bus_port: 1324
3
+ tags:
4
+ localhost_ping:
5
+ type: ping
6
+ addr: '127.0.0.1'
7
+ electronet_ping:
8
+ type: ping
9
+ addr: electronet.co.nz
10
+ google_ping:
11
+ type: ping
12
+ addr: www.google.com
@@ -0,0 +1,15 @@
1
+ [Unit]
2
+ Description=pymscada - Ping client
3
+ BindsTo=pymscada-bus.service
4
+ After=pymscada-bus.service
5
+
6
+ [Service]
7
+ WorkingDirectory=__DIR__
8
+ ExecStart=__PYMSCADA__ ping --config __DIR__/config/ping.yaml
9
+ Restart=always
10
+ RestartSec=5
11
+ User=mscada
12
+ Group=mscada
13
+
14
+ [Install]
15
+ WantedBy=multi-user.target
pymscada/demo/tags.yaml CHANGED
@@ -253,4 +253,13 @@ Router_eth8_bytes_in:
253
253
  type: int
254
254
  Router_eth8_bytes_out:
255
255
  desc: eth8 bytes out
256
- type: int
256
+ type: int
257
+ localhost_ping:
258
+ desc: Ping time to localhost
259
+ units: ms
260
+ google_ping:
261
+ desc: Ping time to google
262
+ units: ms
263
+ electronet_ping:
264
+ desc: Ping time to electronet
265
+ units: ms
@@ -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
@@ -1,6 +1,5 @@
1
1
  """Modbus Client."""
2
2
  import asyncio
3
- from itertools import chain
4
3
  import logging
5
4
  from struct import pack, unpack_from
6
5
  from pymscada.bus_client import BusClient
@@ -76,7 +75,7 @@ class ModbusClientConnector:
76
75
  """Poll Modbus device, write on change in write range."""
77
76
 
78
77
  def __init__(self, name: str, ip: str, port: int, rate: int, tcp_udp: str,
79
- read: list, writeok: list, mapping: ModbusMaps):
78
+ poll: list, mapping: ModbusMaps):
80
79
  """
81
80
  Set up polling client.
82
81
 
@@ -88,13 +87,13 @@ class ModbusClientConnector:
88
87
  self.tcp_udp = tcp_udp
89
88
  self.transport = None
90
89
  self.protocol = None
91
- self.read = read
92
- self.writeok = writeok
90
+ self.read = poll
91
+ self.writeok = None
93
92
  self.periodic = Periodic(self.poll, rate)
94
93
  self.mapping = mapping
95
94
  self.sent = {}
96
95
  tables = {}
97
- for file_range in chain(read, writeok):
96
+ for file_range in poll: # chain(read, writeok):
98
97
  unit = file_range['unit']
99
98
  file = file_range['file']
100
99
  table = f'{name}:{unit}:{file}'
@@ -139,7 +139,7 @@ class ModbusMaps():
139
139
  """Make the maps."""
140
140
  for tagname, v in self.tags.items():
141
141
  dtype = v['type']
142
- addr = v['addr']
142
+ addr = v['read']
143
143
  map = ModbusMap(tagname, dtype, addr, self.data, self.value_chg)
144
144
  size = DTYPES[dtype][3]
145
145
  name, unit, file, word = addr.split(':')