pymscada 0.1.11__py3-none-any.whl → 0.1.11b2__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.
@@ -16,17 +16,17 @@ rarely.
16
16
  - data size of 8-bit char
17
17
 
18
18
  command
19
- - CMD_ID data is tagname
19
+ - CMD.ID data is tagname
20
20
  - reply: CMD_ID with tag_id and data as tagname
21
- - CMD_SET id, data is typed or json packed
21
+ - CMD.SET id, data is typed or json packed
22
22
  - no reply
23
- - CMD_UNSUB id
23
+ - CMD.UNSUB id
24
24
  - no reply
25
- - CMD_GET id
26
- - CMD_RTA id, data is request to author
27
- - CMD_SUB id
25
+ - CMD.GET id
26
+ - CMD.RTA id, data is request to author
27
+ - CMD.SUB id
28
28
  - reply: SET id and value, value may be None
29
- - CMD_LIST
29
+ - CMD.LIST
30
30
  - size == 0x00
31
31
  - tags with values newer than time_us
32
32
  - size > 0x00
@@ -34,43 +34,33 @@ command
34
34
  - text$ matches start of tagname
35
35
  - text matches anywhere in tagname
36
36
  - reply: LIST data as space separated tagnames
37
- - CMD_LOG data to logging.warning
37
+ - CMD.LOG data to logging.warning
38
38
  """
39
39
 
40
40
  # Tuning constants
41
41
  MAX_LEN = 65535 - 14 # TODO fix server(?) when 3
42
42
 
43
- # Network protocol commands
44
- CMD_ID = 1 # query / inform tag ID - data is tagname bytes string
45
- CMD_SET = 2 # set a tag
46
- CMD_GET = 3 # get a tag
47
- CMD_RTA = 4 # request to author
48
- CMD_SUB = 5 # subscribe to a tag
49
- CMD_UNSUB = 6 # unsubscribe from a tag
50
- CMD_LIST = 7 # bus list tags
51
- CMD_ERR = 8 # action failed
52
- CMD_LOG = 9 # bus print a logging message
43
+ from enum import IntEnum
53
44
 
54
- CMD_TEXT = {
55
- 1: 'CMD_ID',
56
- 2: 'CMD_SET',
57
- 3: 'CMD_GET',
58
- 4: 'CMD_RTA',
59
- 5: 'CMD_SUB',
60
- 6: 'CMD_UNSUB',
61
- 7: 'CMD_LIST',
62
- 8: 'CMD_ERR',
63
- 9: 'CMD_LOG'
64
- }
45
+ class COMMAND(IntEnum):
46
+ ID = 1 # query / inform tag ID - data is tagname bytes string
47
+ SET = 2 # set a tag
48
+ GET = 3 # get a tag
49
+ RTA = 4 # request to author
50
+ SUB = 5 # subscribe to a tag
51
+ UNSUB = 6 # unsubscribe from a tag
52
+ LIST = 7 # bus list tags
53
+ ERR = 8 # action failed
54
+ LOG = 9 # bus print a logging message
65
55
 
66
- COMMANDS = [CMD_ID, CMD_SET, CMD_GET, CMD_RTA, CMD_SUB, CMD_UNSUB, CMD_LIST,
67
- CMD_ERR, CMD_LOG]
56
+ @staticmethod
57
+ def text(cmd) -> str:
58
+ """Return command text description for enum or int."""
59
+ return COMMAND(cmd).name
68
60
 
69
- # data types
70
- TYPE_INT = 1 # 64 bit signed integer
71
- TYPE_FLOAT = 2 # 64 bit IEEE float
72
- TYPE_STR = 3 # string
73
- TYPE_BYTES = 4
74
- TYPE_JSON = 5
75
-
76
- TYPES = [TYPE_INT, TYPE_FLOAT, TYPE_STR, TYPE_BYTES, TYPE_JSON]
61
+ class TYPE(IntEnum):
62
+ INT = 1 # 64 bit signed integer
63
+ FLOAT = 2 # 64 bit IEEE float
64
+ STR = 3 # string
65
+ BYTES = 4 # raw bytes
66
+ JSON = 5 # JSON encoded data
pymscada/validate.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """Config file validation."""
2
2
  from cerberus import Validator
3
+ import logging
3
4
  from yaml import dump
4
5
  from pymscada import Config
5
6
  from socket import inet_aton
@@ -106,17 +107,15 @@ SELECTDICT_LIST = {
106
107
  'required': False
107
108
  }
108
109
  }
110
+ OPNOTE_LIST = {
111
+ 'type': {'type': 'string', 'allowed': ['opnote']},
112
+ 'site': {'type': 'list'},
113
+ 'by': {'type': 'list'}
114
+ }
109
115
  UPLOT_LIST = {
110
116
  'type': {'type': 'string', 'allowed': ['uplot']},
111
117
  'ms': {
112
118
  'type': 'dict',
113
- # 'schema': {
114
- # 'type': 'dict',
115
- # # 'schema': {
116
- # # 'type': {'type': 'string', 'required': False},
117
- # # 'multi': {'type': 'list', 'required': False},
118
- # # }
119
- # },
120
119
  'required': False
121
120
  },
122
121
  'axes': {
@@ -160,7 +159,7 @@ LIST_WWWSERVER = {
160
159
  'type': 'dict',
161
160
  'oneof_schema': [
162
161
  BRHR_LIST, H123P_LIST, VALUESETFILES_LIST,
163
- SELECTDICT_LIST, UPLOT_LIST
162
+ SELECTDICT_LIST, OPNOTE_LIST, UPLOT_LIST
164
163
  ]
165
164
  }
166
165
  },
@@ -175,6 +174,7 @@ WWWSERVER_SCHEMA = {
175
174
  'ip': {'type': 'string', 'ms_ip': 'none ipv4'},
176
175
  'port': {'type': 'integer', 'min': 1024, 'max': 65536},
177
176
  'get_path': {'nullable': True},
177
+ 'serve_path': {'nullable': True},
178
178
  'paths': {'type': 'list', 'allowed': ['history', 'config', 'pdf']},
179
179
  'pages': {
180
180
  'type': 'list',
@@ -361,6 +361,13 @@ class MsValidator(Validator):
361
361
  ms_tagnames = {}
362
362
  ms_notagcheck = {}
363
363
 
364
+ def __init__(self, *args, **kwargs):
365
+ super().__init__(*args, **kwargs)
366
+ self.context = {
367
+ 'current_file': None,
368
+ 'current_section': None
369
+ }
370
+
364
371
  def _validate_ms_tagname(self, constraint, field, value):
365
372
  """
366
373
  Test tagname exists, capture when true.
@@ -369,15 +376,15 @@ class MsValidator(Validator):
369
376
  {'type': 'string'}
370
377
  """
371
378
  if '.' in field:
372
- self._error(field, "'.' invalid in tag definition.")
379
+ self._error(field, f"'.' invalid in tag definition in {self.context['current_file']}")
373
380
  if constraint == 'save':
374
381
  if field in self.ms_tagnames:
375
- self._error(field, 'attempt to redefine')
382
+ self._error(field, f"attempt to redefine in {self.context['current_file']}")
376
383
  else:
377
384
  self.ms_tagnames[field] = {'type': None}
378
385
  elif constraint == 'exists':
379
386
  if value not in self.ms_tagnames:
380
- self._error(field, 'tag was not defined in tags.yaml')
387
+ self._error(field, f"tag '{value}' was not defined in tags.yaml")
381
388
  elif constraint == 'none':
382
389
  pass
383
390
  else:
@@ -429,20 +436,16 @@ def validate(path: str = None):
429
436
  'snmpclient': SNMPCLIENT_SCHEMA,
430
437
  'logixclient': LOGIXCLIENT_SCHEMA,
431
438
  }
432
- prefix = './'
433
- if path is not None:
434
- prefix = path + '/'
435
- c = {
436
- 'tags': dict(Config(f'{prefix}tags.yaml')),
437
- 'bus': dict(Config(f'{prefix}bus.yaml')),
438
- 'wwwserver': dict(Config(f'{prefix}wwwserver.yaml')),
439
- 'history': dict(Config(f'{prefix}history.yaml')),
440
- 'modbusserver': dict(Config(f'{prefix}modbusserver.yaml')),
441
- 'modbusclient': dict(Config(f'{prefix}modbusclient.yaml')),
442
- 'snmpclient': dict(Config(f'{prefix}snmpclient.yaml')),
443
- 'logixclient': dict(Config(f'{prefix}logixclient.yaml')),
444
- }
445
439
  v = MsValidator(s)
440
+ c = {}
441
+ prefix = './' if path is None else f"{path}/"
442
+ for name in s.keys():
443
+ try:
444
+ v.context['current_file'] = f'{name}.yaml'
445
+ v.context['current_section'] = name
446
+ c[name] = dict(Config(f'{prefix}{name}.yaml'))
447
+ except Exception as e:
448
+ v._error(name, f'Failed to load {name}.yaml: {str(e)}')
449
+ return False, dump(v.errors), prefix
446
450
  res = v.validate(c)
447
- wdy = dump(v.errors) # , default_flow_style=False)
448
- return res, wdy, prefix
451
+ return res, dump(v.errors), prefix
pymscada/www_server.py CHANGED
@@ -83,7 +83,7 @@ class WSHandler():
83
83
  self.queue.put_nowait((True, pack(
84
84
  '!HHQq', # Network big-endian
85
85
  tag.id, # Uint16
86
- pc.TYPE_INT, # Uint16
86
+ pc.TYPE.INT, # Uint16
87
87
  tag.time_us, # Uint64
88
88
  tag.value # Int64
89
89
  )))
@@ -91,7 +91,7 @@ class WSHandler():
91
91
  self.queue.put_nowait((True, pack(
92
92
  '!HHQd', # Network big-endian
93
93
  tag.id, # Uint16
94
- pc.TYPE_FLOAT, # Uint16
94
+ pc.TYPE.FLOAT, # Uint16
95
95
  tag.time_us, # Uint64
96
96
  tag.value # Float64
97
97
  )))
@@ -100,7 +100,7 @@ class WSHandler():
100
100
  self.queue.put_nowait((True, pack(
101
101
  f'!HHQ{len(asbytes)}s', # Network big-endian
102
102
  tag.id, # Uint16
103
- pc.TYPE_STR, # Uint16
103
+ pc.TYPE.STR, # Uint16
104
104
  tag.time_us, # Uint64
105
105
  asbytes # Char as needed
106
106
  )))
@@ -110,7 +110,7 @@ class WSHandler():
110
110
  self.queue.put_nowait((True, pack(
111
111
  f'!HHQ{len(tag.value)}s', # Network big-endian
112
112
  tag.id, # Uint16
113
- pc.TYPE_BYTES, # Uint16
113
+ pc.TYPE.BYTES, # Uint16
114
114
  tag.time_us, # Uint64
115
115
  tag.value # Char as needed
116
116
  )))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pymscada
3
- Version: 0.1.11
3
+ Version: 0.1.11b2
4
4
  Summary: Shared tag value SCADA with python backup and Angular UI
5
5
  Author-Email: Jamie Walton <jamie@walton.net.nz>
6
6
  License: GPL-3.0-or-later
@@ -11,11 +11,11 @@ Classifier: Operating System :: OS Independent
11
11
  Classifier: Environment :: Console
12
12
  Classifier: Development Status :: 1 - Planning
13
13
  Project-URL: Homepage, https://github.com/jamie0walton/pymscada
14
- Project-URL: Bug tracker, https://github.com/jamie0walton/pymscada/issues
14
+ Project-URL: Bug Tracker, https://github.com/jamie0walton/pymscada/issues
15
15
  Requires-Python: >=3.9
16
16
  Requires-Dist: PyYAML>=6.0.1
17
17
  Requires-Dist: aiohttp>=3.8.5
18
- Requires-Dist: pymscada-html>=0.1.2
18
+ Requires-Dist: pymscada-html>=0.1.10b2
19
19
  Requires-Dist: cerberus>=1.3.5
20
20
  Requires-Dist: pycomm3>=1.2.14
21
21
  Requires-Dist: pysnmplib>=5.0.24
@@ -1,14 +1,14 @@
1
- pymscada-0.1.11.dist-info/METADATA,sha256=itDYWXs3JwiNNw8EJCAtxZ6tjVmQyrnO4ufYA-xgFLw,2344
2
- pymscada-0.1.11.dist-info/WHEEL,sha256=pM0IBB6ZwH3nkEPhtcp50KvKNX-07jYtnb1g1m6Z4Co,90
3
- pymscada-0.1.11.dist-info/entry_points.txt,sha256=j_UgZmqFhNquuFC2M8g5-8X9FCpp2RaDb7NrExzkj1c,72
4
- pymscada-0.1.11.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
1
+ pymscada-0.1.11b2.dist-info/METADATA,sha256=ha12v3EbpjwJ8bTiLYLCGsVFVGny1Yz0LQzDWlOiGks,2349
2
+ pymscada-0.1.11b2.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ pymscada-0.1.11b2.dist-info/entry_points.txt,sha256=j_UgZmqFhNquuFC2M8g5-8X9FCpp2RaDb7NrExzkj1c,72
4
+ pymscada-0.1.11b2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
5
5
  pymscada/__init__.py,sha256=NV_cIIwe66Ugp8ns426rtfJIIyskWbqwImD9p_5p0bQ,739
6
6
  pymscada/__main__.py,sha256=WcyVlrYOoDdktJhOoyubTOycMwpayksFdxwelRU5xpQ,272
7
- pymscada/bus_client.py,sha256=NWumdtLNy4-_LdTumHy687q0ebQX7fdynSp13dZgpYo,8899
8
- pymscada/bus_server.py,sha256=3ZLT2QFfKMndrTVd1TRWk15rYtaXnW1Ls2dlZe5nsyM,11544
7
+ pymscada/bus_client.py,sha256=ZUCynJtEvmHruzLS6ZAzp-_0dv1A1u_POgemb38kHuc,8989
8
+ pymscada/bus_server.py,sha256=8F1beP4NRCBpGJQ0u9NZI1mP6P29HSl6mm9GoGMTCJA,11795
9
9
  pymscada/checkout.py,sha256=N8ZIxtNaP87w2cVRBGA2ib1cijdFfF4xWWZFFVLJa9g,3494
10
10
  pymscada/config.py,sha256=vwGxieaJBYXiHNQEOYVDFaPuGmnUlCnbNm_W9bugKlc,1851
11
- pymscada/console.py,sha256=ujHhOTPYLRQa96wGIEsjdq6r1cOFcEu-Mnl7wqk8mTg,8756
11
+ pymscada/console.py,sha256=b4gm7cuhYKGFNtHoxygWkrqiN42mU8DM4KUi-Q74M4U,8793
12
12
  pymscada/demo/README.md,sha256=iNcVbCTkq-d4agLV-979lNRaqf_hbJCn3OFzY-6qfU8,880
13
13
  pymscada/demo/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
14
14
  pymscada/demo/accuweather.yaml,sha256=rJIiBTUHfaxuYqLLuyKtAe5dqXVdQyEeHJgIy7z-qXo,322
@@ -19,6 +19,7 @@ pymscada/demo/logixclient.yaml,sha256=G_NlJhBYwT1a9ceHDgO6fCNKFmBM2pVO_t9Xa1NqlR
19
19
  pymscada/demo/modbus_plc.py,sha256=3zZHHbyrdxyryEHBeNIw-fpcDGcS1MaJiqEwQDr6zWI,2397
20
20
  pymscada/demo/modbusclient.yaml,sha256=geeCsUJZkkEj7jjXR_Yk6R5zA5Ta9IczrHsARz7ZgXY,1099
21
21
  pymscada/demo/modbusserver.yaml,sha256=67_mED6jXgtnzlDIky9Cg4j-nXur06iz9ve3JUwSyG8,1133
22
+ pymscada/demo/openweather.yaml,sha256=NQ2HL_RlTQ8amYuNQhk09bC7w_rTmIeQ1RsxX1LLtKU,430
22
23
  pymscada/demo/opnotes.yaml,sha256=9z8dO_S6JErMuGQHivR584UPln-5jW8Qzq7gdhTNcxM,107
23
24
  pymscada/demo/ping.yaml,sha256=r_VBGTLU5r4cZi9bIGL3M4eNw70KnoBptOUoNrSbnFY,210
24
25
  pymscada/demo/pymscada-bus.service,sha256=F3ViriRXyMKdCY3tHa3wXAnv2Fo2_16-EScTLsYnSOA,261
@@ -34,8 +35,8 @@ pymscada/demo/pymscada-io-snmpclient.service,sha256=Rsm8uiwnoGx-1MkXqYgtj4UP9-r7
34
35
  pymscada/demo/pymscada-opnotes.service,sha256=TlrTRgP3rzrlXT8isAGT_Wy38ScDjT1VvnlgW84XiS8,354
35
36
  pymscada/demo/pymscada-wwwserver.service,sha256=7Qy2wsMmFEsQn-b5mgAcsrAQZgXynkv8SpHD6hLvRGc,370
36
37
  pymscada/demo/snmpclient.yaml,sha256=z8iACrFvMftYUtqGrRjPZYZTpn7aOXI-Kp675NAM8cU,2013
37
- pymscada/demo/tags.yaml,sha256=GH90X3QRBANUhvd2E9OuyIoiZD25OBihHHlDBw1uzlw,4231
38
- pymscada/demo/wwwserver.yaml,sha256=MhZbvnxAfkc3OutXyZVaVKif4ZD9VSch5NfBbO0T_-E,12597
38
+ pymscada/demo/tags.yaml,sha256=E8pMcLvwwyPBeSIXnu56IoTKfOJ3tnrgR4lpzHyMk4c,4267
39
+ pymscada/demo/wwwserver.yaml,sha256=95TM8V4KMwlPAM1uY50GDGScfZ1xVJrpeoN9m6uluIs,6488
39
40
  pymscada/files.py,sha256=MisnKoWvkffPMSj6sGVmm-4fh866x4UX3t9LJg4oCfk,2400
40
41
  pymscada/history.py,sha256=G079gHfzasmGtI5ANS8MdETD4bdZg5vHE_yTKk7atHw,9504
41
42
  pymscada/iodrivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -45,22 +46,24 @@ pymscada/iodrivers/logix_map.py,sha256=ljjBAMJcw199v1V5u0Yfl38U6zbZzba5mdY4I3Zvd
45
46
  pymscada/iodrivers/modbus_client.py,sha256=DIGrEPz_Bwwj9CEeog5fQqiAu1UMV7xVL6KxlKgXNPs,9592
46
47
  pymscada/iodrivers/modbus_map.py,sha256=af2J3CGSeYQ4mSy8rNsERp9z7fRgRUYk3it5Mrc_IQA,7255
47
48
  pymscada/iodrivers/modbus_server.py,sha256=VqvjOJ4-LOVaD1jOK22raXhrCshJEaWlMxLvn5xMnFc,6570
49
+ pymscada/iodrivers/openweather.py,sha256=ftFLXp5qAQ1G3dx8zKH1ZrhoW6E2kQTqBOnT7XE0wcQ,5467
48
50
  pymscada/iodrivers/ping_client.py,sha256=UOQgUfoIcYqy5VvKyJ8XGHHjeSRTfjmrhyWEojhIZQk,4188
49
51
  pymscada/iodrivers/ping_map.py,sha256=EbOteqfEYKIOMqPymROJ4now2If-ekEj6jnM5hthoSA,1403
50
52
  pymscada/iodrivers/snmp_client.py,sha256=66-IDzddeKcSnqOzNXIZ8wuuAqhIxZjyLNrDwDvHCvw,2708
51
53
  pymscada/iodrivers/snmp_map.py,sha256=sDdIR5ZPAETpozDfBt_XQiZ-f4t99UCPlzj7BxFxQyM,2369
52
- pymscada/main.py,sha256=6F8a8y_rHYUZnc5JBWPJhT-z4M7d134tA_l3QNfbm3A,8469
54
+ pymscada/main.py,sha256=XtASmPZoQMuzDCHlH3P9XwgYskeLtNdl-hc1tDI7ljc,1875
53
55
  pymscada/misc.py,sha256=0Cj6OFhQonyhyk9x0BG5MiS-6EPk_w6zvavt8o_Hlf0,622
56
+ pymscada/module_config.py,sha256=aGa6MArf-81vaB9r83MfCfW7ERYC9Ftj0AglsRm7_08,7620
54
57
  pymscada/opnotes.py,sha256=pxjFgy4uMnAmJcfrk8BX4Gl5j0z4fFb5waXcqI6UJ_M,5133
55
58
  pymscada/pdf/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
56
59
  pymscada/pdf/one.pdf,sha256=eoJ45DrAjVZrwmwdA_EAz1fwmT44eRnt_tkc2pmMrKY,1488
57
60
  pymscada/pdf/two.pdf,sha256=TAuW5yLU1_wfmTH_I5ezHwY0pxhCVuZh3ixu0kwmJwE,1516
58
61
  pymscada/periodic.py,sha256=MLlL93VLvFqBBgjO1Us1t0aLHTZ5BFdW0B__G02T1nQ,1235
59
- pymscada/protocol_constants.py,sha256=scqu_vecB4U8WxbFbn3mdIhKuZWgNO7fyd-RMP5O_14,2094
62
+ pymscada/protocol_constants.py,sha256=ooGmBM7WGWWdN10FObdjzcYieK8WN7Zy6qVxtD93LMk,1963
60
63
  pymscada/samplers.py,sha256=t0IscgsCm5YByioOZ6aOKMO_guDFS_wxnJSiOGKI4Nw,2583
61
64
  pymscada/tag.py,sha256=Oxh70q2MrPAEI94v4QsWt4gD8QP6BlfzNv9xXeeUFys,10103
62
65
  pymscada/tools/snmp_client2.py,sha256=pdn5dYyEv4q-ubA0zQ8X-3tQDYxGC7f7Xexa7QPaL40,1675
63
66
  pymscada/tools/walk.py,sha256=OgpprUbKLhEWMvJGfU1ckUt_PFEpwZVOD8HucCgzmOc,1625
64
- pymscada/validate.py,sha256=VPpAVEwfgori5OREEwWlbPoPxz5Tfqr6dw-O5pINHyI,13125
65
- pymscada/www_server.py,sha256=bDa3Mh1Dcjk67yk3nPd6HadWF8GjoDYY1t_1g8mfmdk,12021
66
- pymscada-0.1.11.dist-info/RECORD,,
67
+ pymscada/validate.py,sha256=fPMlP6RscYuTIgdEJjJ0ZZI0OyVSat1lpqg254wqpdE,13140
68
+ pymscada/www_server.py,sha256=rV1Vsk3J1wBhFMBCnK33SziNuTGgVwNc5zLjQQFxJ-s,12021
69
+ pymscada-0.1.11b2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.2)
2
+ Generator: pdm-backend (2.4.3)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any