pymscada 0.1.11b10__py3-none-any.whl → 0.2.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.
pymscada/www_server.py CHANGED
@@ -4,13 +4,36 @@ from aiohttp import web, WSMsgType
4
4
  import logging
5
5
  from pathlib import Path
6
6
  from struct import pack, unpack_from
7
+ import socket
7
8
  import time
8
9
  from pymscada.bus_client import BusClient
9
10
  import pymscada.protocol_constants as pc
10
- from pymscada.tag import Tag, tag_for_web, TYPES
11
+ from pymscada.tag import Tag, TYPES
11
12
  from pymscada_html import get_html_file
12
13
 
13
14
 
15
+ def standardise_tag_info(tagname: str, tag: dict):
16
+ """Correct tag dictionary in place to be suitable for web client."""
17
+ tag['name'] = tagname
18
+ tag['id'] = None
19
+ if 'desc' not in tag:
20
+ tag['desc'] = tagname
21
+ if 'multi' in tag:
22
+ tag['type'] = 'int'
23
+ else:
24
+ if 'type' not in tag:
25
+ tag['type'] = 'float'
26
+ else:
27
+ if tag['type'] not in TYPES:
28
+ tag['type'] = 'str'
29
+ if tag['type'] == 'int':
30
+ tag['dp'] = 0
31
+ elif tag['type'] == 'float' and 'dp' not in tag:
32
+ tag['dp'] = 2
33
+ elif tag['type'] == 'str' and 'dp' in tag:
34
+ del tag['dp']
35
+
36
+
14
37
  class Interface():
15
38
  """Provide an interface between web client rta and the action."""
16
39
 
@@ -34,11 +57,13 @@ class WSHandler():
34
57
  ids = set(range(1, 1000))
35
58
 
36
59
  def __init__(self, ws: web.WebSocketResponse, pages: dict,
37
- tag_info: dict[str, Tag], do_rta, interface: Interface):
60
+ tag_info: dict[str, Tag], do_rta, interface: Interface,
61
+ config: dict):
38
62
  """Create callbacks to monitor tag values."""
39
63
  self.ws = ws
40
64
  self.pages = pages
41
65
  self.tag_info = tag_info
66
+ self.config = config
42
67
  self.tag_by_id: dict[int, Tag] = {}
43
68
  self.tag_by_name: dict[str, Tag] = {}
44
69
  self.queue = asyncio.Queue()
@@ -140,7 +165,7 @@ class WSHandler():
140
165
 
141
166
  def notify_id(self, tag: Tag):
142
167
  """Must be done here."""
143
- logging.info(f'{self.rta_id}: send id to webclient for {tag.name}')
168
+ logging.info(f'{self.rta_id}: send id to browser for {tag.name}')
144
169
  self.tag_info[tag.name]['id'] = tag.id
145
170
  self.tag_by_id[tag.id] = tag
146
171
  self.tag_by_name[tag.name] = tag
@@ -168,6 +193,8 @@ class WSHandler():
168
193
  async def connection_active(self):
169
194
  """Run while the connection is active and don't return."""
170
195
  send_queue = asyncio.create_task(self.send_queue())
196
+ self.queue.put_nowait(
197
+ (False, {'type': 'config', 'payload': self.config}))
171
198
  self.queue.put_nowait(
172
199
  (False, {'type': 'pages', 'payload': self.pages}))
173
200
  async for msg in self.ws:
@@ -208,32 +235,60 @@ class WSHandler():
208
235
 
209
236
 
210
237
  class WwwServer:
211
- """Connect to bus on bus_ip:bus_port, serve on ip:port for webclient."""
238
+ """Connect to bus on bus_ip:bus_port, serve on ip:port for webserver."""
212
239
 
213
- def __init__(self, bus_ip: str = '127.0.0.1', bus_port: int = 1324,
214
- ip: str = '127.0.0.1', port: int = 8324, get_path: str = None,
215
- tag_info: dict = {}, pages: dict = {}, serve_path: str = None,
216
- www_tag: str = '__wwwserver__'
217
- ) -> None:
240
+ def __init__(
241
+ self,
242
+ bus_ip: str = '127.0.0.1',
243
+ bus_port: int = 1324,
244
+ ip: str = '127.0.0.1',
245
+ port: int = 8324,
246
+ get_path: str | None = None,
247
+ tag_info: dict = {},
248
+ pages: dict = {},
249
+ config: dict = {},
250
+ serve_path: str | None = None,
251
+ www_tag: str = '__wwwserver__'
252
+ ) -> None:
218
253
  """
219
- Connect to bus on bus_ip:bus_port, serve on ip:port for webclient.
254
+ Connect to bus on bus_ip:bus_port, serve on ip:port for webserver.
220
255
 
221
- Serves the webclient files at /, as a relative path. The webclient uses
222
- a websocket connection to request and set tag values and subscribe to
256
+ Serves the files at /, as a relative path. The browser uses a
257
+ websocket connection to request and set tag values and subscribe to
223
258
  changes.
224
259
 
225
260
  Event loop must be running.
226
261
  """
262
+ try:
263
+ socket.gethostbyname(bus_ip)
264
+ except socket.gaierror as e:
265
+ raise ValueError(f'Cannot resolve bus IP/hostname: {e}')
266
+ if not isinstance(bus_port, int):
267
+ raise TypeError('bus_port must be an integer')
268
+ if not 1024 <= bus_port <= 65535:
269
+ raise ValueError('bus_port must be between 1024 and 65535')
270
+ try:
271
+ socket.gethostbyname(ip)
272
+ except socket.gaierror as e:
273
+ raise ValueError(f'Cannot resolve IP/hostname: {e}')
274
+ if not isinstance(port, int):
275
+ raise TypeError('port must be an integer')
276
+ if not 1024 <= port <= 65535:
277
+ raise ValueError('port must be between 1024 and 65535')
278
+ if not isinstance(www_tag, str) or not www_tag:
279
+ raise ValueError('www_tag must be a non-empty string')
280
+
227
281
  self.busclient = BusClient(bus_ip, bus_port, tag_info,
228
282
  module='WWW Server')
229
283
  self.ip = ip
230
284
  self.port = port
231
285
  self.get_path = get_path
232
- self.serve_path = Path(serve_path)
286
+ self.serve_path = Path(serve_path) if serve_path else None
233
287
  for tagname, tag in tag_info.items():
234
- tag_for_web(tagname, tag)
288
+ standardise_tag_info(tagname, tag)
235
289
  self.tag_info = tag_info
236
290
  self.pages = pages
291
+ self.config = config
237
292
  self.interface = Interface(www_tag)
238
293
 
239
294
  async def redirect_handler(self, _request: web.Request):
@@ -256,14 +311,14 @@ class WwwServer:
256
311
  async def path_handler(self, request: web.Request):
257
312
  """Plain files."""
258
313
  logging.info(f"path {request.match_info['path']}")
314
+ if self.serve_path is None:
315
+ return web.HTTPForbidden(reason='path not configured')
259
316
  path = self.serve_path.joinpath(request.match_info['path'])
260
317
  if path.is_dir():
261
318
  return web.HTTPForbidden(reason='folder not permitted')
262
319
  if not path.exists():
263
320
  return web.HTTPNotFound(reason='no such file in path')
264
321
  return web.FileResponse(path)
265
- # logging.warning(f"path not configured {request.match_info['path']}")
266
- # return web.HTTPForbidden(reason='path not permitted')
267
322
 
268
323
  async def websocket_handler(self, request: web.Request):
269
324
  """Wait for connections. Create a new one each time."""
@@ -272,7 +327,7 @@ class WwwServer:
272
327
  ws = web.WebSocketResponse(max_msg_size=0) # disables max message size
273
328
  await ws.prepare(request)
274
329
  await WSHandler(ws, self.pages, self.tag_info, self.busclient.rta,
275
- self.interface).connection_active()
330
+ self.interface, self.config).connection_active()
276
331
  await ws.close()
277
332
  logging.info(f"WS closed {peer}")
278
333
  return ws
@@ -1,25 +1,27 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pymscada
3
- Version: 0.1.11b10
3
+ Version: 0.2.0
4
4
  Summary: Shared tag value SCADA with python backup and Angular UI
5
- Author-Email: Jamie Walton <jamie@walton.net.nz>
5
+ Author-email: Jamie Walton <jamie@walton.net.nz>
6
6
  License: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/jamie0walton/pymscada
8
+ Project-URL: Bug Tracker, https://github.com/jamie0walton/pymscada/issues
7
9
  Classifier: Programming Language :: Python :: 3
8
10
  Classifier: Programming Language :: JavaScript
9
11
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
12
  Classifier: Operating System :: OS Independent
11
13
  Classifier: Environment :: Console
12
14
  Classifier: Development Status :: 1 - Planning
13
- Project-URL: Homepage, https://github.com/jamie0walton/pymscada
14
- Project-URL: Bug Tracker, https://github.com/jamie0walton/pymscada/issues
15
15
  Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
16
18
  Requires-Dist: PyYAML>=6.0.1
17
19
  Requires-Dist: aiohttp>=3.8.5
18
- Requires-Dist: pymscada-html>=0.1.10b5
20
+ Requires-Dist: pymscada-html==0.2.0rc4
19
21
  Requires-Dist: cerberus>=1.3.5
20
22
  Requires-Dist: pycomm3>=1.2.14
21
23
  Requires-Dist: pysnmplib>=5.0.24
22
- Description-Content-Type: text/markdown
24
+ Dynamic: license-file
23
25
 
24
26
  # pymscada
25
27
  #### [Docs](https://github.com/jamie0walton/pymscada/blob/main/docs/README.md)
@@ -1,44 +1,59 @@
1
- pymscada-0.1.11b10.dist-info/METADATA,sha256=eBGZjmCSP1HPBnfBlpacMN1Q2VdGFm0_52G2FU-TlLg,2350
2
- pymscada-0.1.11b10.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- pymscada-0.1.11b10.dist-info/entry_points.txt,sha256=j_UgZmqFhNquuFC2M8g5-8X9FCpp2RaDb7NrExzkj1c,72
4
- pymscada-0.1.11b10.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
5
1
  pymscada/__init__.py,sha256=NV_cIIwe66Ugp8ns426rtfJIIyskWbqwImD9p_5p0bQ,739
6
2
  pymscada/__main__.py,sha256=WcyVlrYOoDdktJhOoyubTOycMwpayksFdxwelRU5xpQ,272
7
- pymscada/bus_client.py,sha256=ZUCynJtEvmHruzLS6ZAzp-_0dv1A1u_POgemb38kHuc,8989
8
- pymscada/bus_server.py,sha256=eD4Fz4Sv4EIu2vney_d0jAryiCk5eoH5NQA-dAZRTqA,12029
9
- pymscada/checkout.py,sha256=1Al29nVqCebupYvMgcY5boz772PtsVp1MVbYaQajV5Q,3373
3
+ pymscada/alarms.py,sha256=eo-9-DSwV825ihuHApaYkADPpLouKbNLHyh0z4bdPoU,12936
4
+ pymscada/bus_client.py,sha256=eRGvHQ4sFM_n3rKvKDWZQJPQJqvKMWvxbH3MjtT2WBo,9131
5
+ pymscada/bus_server.py,sha256=k7ht2SAr24Oab0hBOPeW4NRDF_RK-F46iE0cMzh7K4w,12323
6
+ pymscada/callout.py,sha256=egY-zQmb7Np46qbAxOck_5JbCHgF2x6OLIFunsIU6mc,7435
7
+ pymscada/checkout.py,sha256=RLuCMTEuUI7pp1hIRAUPbo8xYFta8TjArelx0SD4gOY,3897
10
8
  pymscada/config.py,sha256=vwGxieaJBYXiHNQEOYVDFaPuGmnUlCnbNm_W9bugKlc,1851
11
- pymscada/console.py,sha256=b4gm7cuhYKGFNtHoxygWkrqiN42mU8DM4KUi-Q74M4U,8793
9
+ pymscada/console.py,sha256=EEsJLCvn8AFimN8qGNilX0ks6t3OFcGW5nw6OVAXfac,8850
10
+ pymscada/files.py,sha256=iouEOPfEkVI0Qbbf1p-L324Y04zSrynVypLW0-1MThA,2499
11
+ pymscada/history.py,sha256=7UEOeMnlSMv0LoWTqLWx7QwOW1FZZ4wAvzH6v6b0_vI,11592
12
+ pymscada/main.py,sha256=d6EnK4-tEcvM5AqMHYhvqlnSh-E_wd0Tuxk-kXYSiDw,1854
13
+ pymscada/misc.py,sha256=0Cj6OFhQonyhyk9x0BG5MiS-6EPk_w6zvavt8o_Hlf0,622
14
+ pymscada/module_config.py,sha256=K-ZBO-2rZTdlDbVkeQ3_4uI75EUxVMmanVzDuuDNsao,9564
15
+ pymscada/opnotes.py,sha256=MKM51IrB93B2-kgoTzlpOLpaMYs-7rPQHWmRLME-hQQ,7952
16
+ pymscada/periodic.py,sha256=MLlL93VLvFqBBgjO1Us1t0aLHTZ5BFdW0B__G02T1nQ,1235
17
+ pymscada/protocol_constants.py,sha256=lPJ4JEgFJ_puJjTym83EJIOw3UTUFbuFMwg3ohyUAGY,2414
18
+ pymscada/samplers.py,sha256=t0IscgsCm5YByioOZ6aOKMO_guDFS_wxnJSiOGKI4Nw,2583
19
+ pymscada/tag.py,sha256=hTRxogw8BXAi1OJpM1Lhx4KKMqZ53y7D5KcCycO7fRQ,9471
20
+ pymscada/validate.py,sha256=fPMlP6RscYuTIgdEJjJ0ZZI0OyVSat1lpqg254wqpdE,13140
21
+ pymscada/www_server.py,sha256=NfvX9jbVWY2qxWM6TfWUcwsCY7lR-dkty1nCOXyoWTA,13747
12
22
  pymscada/demo/README.md,sha256=iNcVbCTkq-d4agLV-979lNRaqf_hbJCn3OFzY-6qfU8,880
13
23
  pymscada/demo/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
14
24
  pymscada/demo/accuweather.yaml,sha256=Fk4rV0S8jCau0173QCzKW8TdUbc4crYVi0aD8fPLNgU,322
25
+ pymscada/demo/alarms.yaml,sha256=Ea8tLZ0aEiyKM_m5MN1TF6xS-lI5ReXiz2oUPO8GvmQ,110
15
26
  pymscada/demo/bus.yaml,sha256=zde5JDo2Yv5s7NvJ569gAEoTDvsvgBwRPxfrYhsxj3w,26
27
+ pymscada/demo/callout.yaml,sha256=I0nFWEXu1J48tJjKolyeCqvOVnds4FOp3dYBf8cSpcA,298
16
28
  pymscada/demo/files.yaml,sha256=XWtmGDJxtD4qdl2h7miUfJYkDKsvwNTgQjlGpR6LQNs,163
17
29
  pymscada/demo/history.yaml,sha256=c0OuYe8LbTeZqJGU2WKGgTEkOA0IYAjO3e046ddQB8E,55
18
30
  pymscada/demo/logixclient.yaml,sha256=G_NlJhBYwT1a9ceHDgO6fCNKFmBM2pVO_t9Xa1NqlRY,912
19
31
  pymscada/demo/modbus_plc.py,sha256=3zZHHbyrdxyryEHBeNIw-fpcDGcS1MaJiqEwQDr6zWI,2397
20
32
  pymscada/demo/modbusclient.yaml,sha256=geeCsUJZkkEj7jjXR_Yk6R5zA5Ta9IczrHsARz7ZgXY,1099
21
33
  pymscada/demo/modbusserver.yaml,sha256=67_mED6jXgtnzlDIky9Cg4j-nXur06iz9ve3JUwSyG8,1133
22
- pymscada/demo/openweather.yaml,sha256=eFaRc7JxkEwRswCtmJiypsfR5xgQR-R-UtwvfwDHw-w,430
34
+ pymscada/demo/openweather.yaml,sha256=n8aPc_Ar6uiM-XbrEbBydABxFYm2uv_49dGo8u7DI8Q,433
23
35
  pymscada/demo/opnotes.yaml,sha256=gdT8DKaAV4F6u9trLCPyBgf449wYaP_FF8GCbjXm9-k,105
24
36
  pymscada/demo/ping.yaml,sha256=fm3eUdR2BwnPI_lU_V07qgmDxjSoPP6lPazYB6ZgpVg,149
37
+ pymscada/demo/pymscada-alarms.service,sha256=nHjEMsonat-3ny0QJoY6KTZoPIt2HZiarKgW5uasY8k,383
25
38
  pymscada/demo/pymscada-bus.service,sha256=F3ViriRXyMKdCY3tHa3wXAnv2Fo2_16-EScTLsYnSOA,261
39
+ pymscada/demo/pymscada-callout.service,sha256=XpG20TVofjEuoRnBxH1f5DQEBdGbj2tORs60IjiuQw4,386
26
40
  pymscada/demo/pymscada-demo-modbus_plc.service,sha256=EtbWDwqAs4nLNLKScUiHcUWU1b6_tRBeAAVGi9q95hY,320
27
41
  pymscada/demo/pymscada-files.service,sha256=iLOfbl4SCxAwYHT20XCGHU0BJsUVicNHjHzKS8xIdgA,326
28
42
  pymscada/demo/pymscada-history.service,sha256=61c5RqOmJ13Dl1yyRfsChKOdXp2W-xfYyCOYoJHLkh8,386
29
- pymscada/demo/pymscada-io-accuweather.service,sha256=M_dnPYwmvTpYGF5AbMStbYL6VCWgOFR50nRRpfqvpBo,358
30
43
  pymscada/demo/pymscada-io-logixclient.service,sha256=mn4UzkiOfYqHvgfTFSkUeoPFQQXZboet5I0m7-L5SAY,348
31
44
  pymscada/demo/pymscada-io-modbusclient.service,sha256=eTgNdK10dJCs2lLPhmHBh-3j6Ltx2oyU_MNl2f3xnhg,348
32
45
  pymscada/demo/pymscada-io-modbusserver.service,sha256=g7Rzm6zGLq_qvTJRL_pcLl4Ps7CNIa2toeGhPNp_oEc,348
46
+ pymscada/demo/pymscada-io-openweather.service,sha256=SQnZ-cq1V3qvZY7EgR_Vx36vCOw1ipfGoLoutHsxtNk,359
33
47
  pymscada/demo/pymscada-io-ping.service,sha256=Fm8qR4IVq0NupEvHLGONXGwjjQsx5VqaBYPewhg7-k4,329
34
48
  pymscada/demo/pymscada-io-snmpclient.service,sha256=Rsm8uiwnoGx-1MkXqYgtj4UP9-r7AEEeB9yoR0y0oVA,343
49
+ pymscada/demo/pymscada-io-witsapi.service,sha256=ZjNwUnZg7WZsCaBFk8aNibnCbwqtbhl1i9D8tdUGXiQ,343
35
50
  pymscada/demo/pymscada-opnotes.service,sha256=TlrTRgP3rzrlXT8isAGT_Wy38ScDjT1VvnlgW84XiS8,354
36
51
  pymscada/demo/pymscada-wwwserver.service,sha256=7Qy2wsMmFEsQn-b5mgAcsrAQZgXynkv8SpHD6hLvRGc,370
37
52
  pymscada/demo/snmpclient.yaml,sha256=z8iACrFvMftYUtqGrRjPZYZTpn7aOXI-Kp675NAM8cU,2013
38
- pymscada/demo/tags.yaml,sha256=9xydsQriKT0lNAW533rz-FMVgoedn6Lwc50AnNig7-k,2733
53
+ pymscada/demo/tags.yaml,sha256=1HH9SqevBE0P0NXHK0Slfu68gwx5iKpgyirClmAcXGY,2814
54
+ pymscada/demo/witsapi.yaml,sha256=B8F136jvLIYU8t-pOdsEU_j97qMo3RgGQ1Rs4ExhmeE,289
39
55
  pymscada/demo/wwwserver.yaml,sha256=mmwvSLUXUDCIPaHeCJdCETAp9Cc4wb5CuK_aGv01KWk,2759
40
- pymscada/files.py,sha256=MisnKoWvkffPMSj6sGVmm-4fh866x4UX3t9LJg4oCfk,2400
41
- pymscada/history.py,sha256=G079gHfzasmGtI5ANS8MdETD4bdZg5vHE_yTKk7atHw,9504
56
+ pymscada/demo/__pycache__/__init__.cpython-311.pyc,sha256=TC7eGWRbKH4Ym3_tWYBtysWg3sgiWQ19zy81aJLriKQ,195
42
57
  pymscada/iodrivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
58
  pymscada/iodrivers/accuweather.py,sha256=p_OYJtCrtbSQYjgf06Yk3Qc9wGpkx8ogn81XNGd19fE,3842
44
59
  pymscada/iodrivers/logix_client.py,sha256=eqmiYLYUBHbr7wTljomGIZVNvXe-5WleGKfzwcHXO8w,2829
@@ -46,24 +61,22 @@ pymscada/iodrivers/logix_map.py,sha256=ljjBAMJcw199v1V5u0Yfl38U6zbZzba5mdY4I3Zvd
46
61
  pymscada/iodrivers/modbus_client.py,sha256=DIGrEPz_Bwwj9CEeog5fQqiAu1UMV7xVL6KxlKgXNPs,9592
47
62
  pymscada/iodrivers/modbus_map.py,sha256=af2J3CGSeYQ4mSy8rNsERp9z7fRgRUYk3it5Mrc_IQA,7255
48
63
  pymscada/iodrivers/modbus_server.py,sha256=VqvjOJ4-LOVaD1jOK22raXhrCshJEaWlMxLvn5xMnFc,6570
49
- pymscada/iodrivers/openweather.py,sha256=w_OSL5UG30IBTuaR6Exmao7XJae_hKo1JM04XT8Ke7M,5580
64
+ pymscada/iodrivers/openweather.py,sha256=IVzmaEjdwm1NDhsOYpEV5vzB8HFaQEpWsnm6fhpsPCQ,8926
50
65
  pymscada/iodrivers/ping_client.py,sha256=UOQgUfoIcYqy5VvKyJ8XGHHjeSRTfjmrhyWEojhIZQk,4188
51
66
  pymscada/iodrivers/ping_map.py,sha256=EbOteqfEYKIOMqPymROJ4now2If-ekEj6jnM5hthoSA,1403
52
67
  pymscada/iodrivers/snmp_client.py,sha256=66-IDzddeKcSnqOzNXIZ8wuuAqhIxZjyLNrDwDvHCvw,2708
53
68
  pymscada/iodrivers/snmp_map.py,sha256=sDdIR5ZPAETpozDfBt_XQiZ-f4t99UCPlzj7BxFxQyM,2369
54
- pymscada/main.py,sha256=XtASmPZoQMuzDCHlH3P9XwgYskeLtNdl-hc1tDI7ljc,1875
55
- pymscada/misc.py,sha256=0Cj6OFhQonyhyk9x0BG5MiS-6EPk_w6zvavt8o_Hlf0,622
56
- pymscada/module_config.py,sha256=Sq9DDND0WotxwdY7mRHG8G-WNPYqWp9fxvx38--kwr0,8462
57
- pymscada/opnotes.py,sha256=pxjFgy4uMnAmJcfrk8BX4Gl5j0z4fFb5waXcqI6UJ_M,5133
69
+ pymscada/iodrivers/witsapi.py,sha256=Ga6JpEQRUciT_LxWW36LsVGkUeWjModtzPoWYIzyzHs,8381
70
+ pymscada/iodrivers/witsapi_POC.py,sha256=dQcR2k1wsLb_cnNqvAB4kJ7FdY0BlcnxiMoepr28Ars,10132
58
71
  pymscada/pdf/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
59
72
  pymscada/pdf/one.pdf,sha256=eoJ45DrAjVZrwmwdA_EAz1fwmT44eRnt_tkc2pmMrKY,1488
60
73
  pymscada/pdf/two.pdf,sha256=TAuW5yLU1_wfmTH_I5ezHwY0pxhCVuZh3ixu0kwmJwE,1516
61
- pymscada/periodic.py,sha256=MLlL93VLvFqBBgjO1Us1t0aLHTZ5BFdW0B__G02T1nQ,1235
62
- pymscada/protocol_constants.py,sha256=ooGmBM7WGWWdN10FObdjzcYieK8WN7Zy6qVxtD93LMk,1963
63
- pymscada/samplers.py,sha256=t0IscgsCm5YByioOZ6aOKMO_guDFS_wxnJSiOGKI4Nw,2583
64
- pymscada/tag.py,sha256=Oxh70q2MrPAEI94v4QsWt4gD8QP6BlfzNv9xXeeUFys,10103
74
+ pymscada/pdf/__pycache__/__init__.cpython-311.pyc,sha256=5Mad2aaeayIDH_0G1eLDNTLHN14smUPFz7K4D4szoRI,194
65
75
  pymscada/tools/snmp_client2.py,sha256=pdn5dYyEv4q-ubA0zQ8X-3tQDYxGC7f7Xexa7QPaL40,1675
66
76
  pymscada/tools/walk.py,sha256=OgpprUbKLhEWMvJGfU1ckUt_PFEpwZVOD8HucCgzmOc,1625
67
- pymscada/validate.py,sha256=fPMlP6RscYuTIgdEJjJ0ZZI0OyVSat1lpqg254wqpdE,13140
68
- pymscada/www_server.py,sha256=rV1Vsk3J1wBhFMBCnK33SziNuTGgVwNc5zLjQQFxJ-s,12021
69
- pymscada-0.1.11b10.dist-info/RECORD,,
77
+ pymscada-0.2.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
78
+ pymscada-0.2.0.dist-info/METADATA,sha256=us-TxGOsrM-izAAvIzc48J1uwRDQ4-ulToU_jYdm40I,2390
79
+ pymscada-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
80
+ pymscada-0.2.0.dist-info/entry_points.txt,sha256=2UJBi8jrqujnerrcXcq4F8GHJYVDt26sacXl94t3sd8,56
81
+ pymscada-0.2.0.dist-info/top_level.txt,sha256=LxIB-zrtgObJg0fgdGZXBkmNKLDYHfaH1Hw2YP2ZMms,9
82
+ pymscada-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.3)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
+
@@ -1,5 +1,2 @@
1
1
  [console_scripts]
2
2
  pymscada = pymscada.__main__:cmd_line
3
-
4
- [gui_scripts]
5
-
@@ -0,0 +1 @@
1
+ pymscada